Come funziona "questa" parola chiave all'interno di una funzione?


248

Mi sono appena imbattuto in una situazione interessante in JavaScript. Ho una classe con un metodo che definisce diversi oggetti usando la notazione letterale oggetto. All'interno di quegli oggetti, thisviene utilizzato il puntatore. Dal comportamento del programma, ho dedotto che il thispuntatore si riferisce alla classe su cui è stato invocato il metodo e non all'oggetto creato dal letterale.

Sembra arbitrario, sebbene sia il modo in cui mi aspetterei che funzioni. Questo comportamento è definito? È cross-browser sicuro? C'è qualche ragionamento alla base del perché è al di là di "le specifiche lo dicono" (ad esempio, è una conseguenza di una più ampia decisione / filosofia progettuale)? Esempio di codice ridotto:

// inside class definition, itself an object literal, we have this function:
onRender: function() {

    this.menuItems = this.menuItems.concat([
        {
            text: 'Group by Module',
            rptletdiv: this
        },
        {
            text: 'Group by Status',
            rptletdiv: this
        }]);
    // etc
}

succede anche quando lo faccio var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};
Deeptechtons,


dai un'occhiata a questo post . Ha una buona spiegazione dei vari usi e comportamenti di questa parola chiave.
Love Hasija,

Risposte:


558

Cannibalizzato da un altro mio post, ecco più di quanto tu abbia mai voluto sapere su questo .

Prima di iniziare, ecco la cosa più importante da tenere a mente su Javascript e da ripetere quando non ha senso. Javascript non ha classi (ES6 classè zucchero sintattico ). Se qualcosa sembra una classe, è un trucco intelligente. Javascript ha oggetti e funzioni . (non è preciso al 100%, le funzioni sono solo oggetti, ma a volte può essere utile pensarli come cose separate)

Il questa variabile è collegato alle funzioni. Ogni volta che si richiama una funzione, questa viene dato un certo valore, a seconda di come si richiama la funzione. Questo è spesso chiamato il modello di invocazione.

Esistono quattro modi per richiamare le funzioni in JavaScript. È possibile richiamare la funzione come metodo , come funzione , come costruttore e con apply .

Come metodo

Un metodo è una funzione collegata a un oggetto

var foo = {};
foo.someMethod = function(){
    alert(this);
}

Se invocato come metodo, questo sarà associato all'oggetto di cui fa parte la funzione / metodo. In questo esempio, questo sarà legato a pippo.

Come una funzione

Se si dispone di una funzione autonoma, questa variabile verrà associata all'oggetto "globale", quasi sempre l' oggetto finestra nel contesto di un browser.

 var foo = function(){
    alert(this);
 }
 foo();

Questo potrebbe essere ciò che ti fa inciampare , ma non stare male. Molte persone considerano questa una cattiva decisione di progettazione. Poiché un callback viene invocato come funzione e non come metodo, ecco perché stai vedendo quello che sembra essere un comportamento incoerente.

Molte persone aggirano il problema facendo qualcosa di simile, ehm, questo

var foo = {};
foo.someMethod = function (){
    var that=this;
    function bar(){
        alert(that);
    }
}

Definisci una variabile ciò che punta a questo . Chiusura (un argomento tutto è proprio) mantiene quel giro, quindi se si chiama bar come un callback, ha ancora un punto di riferimento.

NOTA: in use strictmodalità se utilizzato come funzione, thisnon è associato a globale. (Lo è undefined).

Come costruttore

Puoi anche invocare una funzione come costruttore. In base alla convenzione di denominazione che stai utilizzando (TestObject), questo potrebbe anche essere ciò che stai facendo ed è ciò che ti fa inciampare .

Si richiama una funzione come costruttore con la nuova parola chiave.

function Foo(){
    this.confusing = 'hell yeah';
}
var myObject = new Foo();

Quando viene invocato come costruttore, verrà creato un nuovo oggetto e questo sarà associato a quell'oggetto. Ancora una volta, se hai funzioni interne e sono usate come callback, le invocherai come funzioni e questo sarà legato all'oggetto globale. Usa quel var che = questo trucco / schema.

Alcune persone pensano che il costruttore / nuova parola chiave sia stato un osso lanciato ai programmatori OOP Java / tradizionali come un modo per creare qualcosa di simile alle classi.

Con il metodo Apply

Infine, ogni funzione ha un metodo (sì, le funzioni sono oggetti in Javascript) chiamato "applica". Applica ti consente di determinare quale sarà il valore di questo e ti consente anche di passare una serie di argomenti. Ecco un esempio inutile.

function foo(a,b){
    alert(a);
    alert(b);
    alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);

8
Nota: in modalità rigorosa , thissarà undefinedper invocazioni di funzioni.
Miscreant

1
Una dichiarazione di funzione, ad es. function myfunction () {}, è un caso speciale di "come metodo" in cui "this" è l'ambito globale (finestra).
Richard

1
@richard: eccetto in modalità rigorosa e thisnon ha nulla a che fare con l'ambito. Intendi l' oggetto globale .
TJ Crowder,

@ alan-storm. Nel caso di "Come costruttore" è this.confusing = 'hell yeah';uguale a var confusing = 'hell yeah';? Quindi entrambi permetteranno myObject.confusing? Sarebbe bello se non solo in modo da poterlo utilizzare thisper creare le proprietà e altre variabili per il lavoro interno.
wunth,

Ma poi suppongo che le cose funzionanti possano essere fatte al di fuori della funzione e che il valore sia passato al costruttore: function Foo(thought){ this.confusing = thought; }e quindivar myObject = new Foo("hell yeah");
wunth,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.