2013-06-12 3 views
5

Ich war einige documentation about javascript und stolperte über den folgenden Code Beispiel zu lesen:Warum verschachtelte lokale Funktion bindet `this` zu Fenster anstelle der Eltern

var o = { 
    value: 1, 
    outer: function() { 
    var inner = function() { 
     console.log(this); //bound to global object 
    }; 
    inner(); 
    } 
}; 
o.outer(); 

Es gibt window.

Ich kann nicht herausfinden, warum das this Schlüsselwort auf das globale Objekt (window) anstelle das übergeordnete Objekt (outer) gebunden ist.
Wenn Sie outer von inner zugreifen wollen ‚s Umfang, müssen Sie die outer passieren‘ s this (die wie outer vorbei an sich ist) in seine lokale inner Funktion als Argument. Also, wie erwartet:

var o = { 
    value: 1, 
    outer: function() { 
    var inner = function (that) { 
     console.log(that); //bound to global object 
    }; 
    inner(this); 
    } 
}; 
o.outer(); 

Ausgänge outer.

Ist es nicht ein bisschen ein Unsinn, dass in outer ‚s Umfang this an das Objekt gebunden ist selbst (dh outer), während in der inner‘ s Rahmen, die outer lokal ist, this ist neu gebunden an das globale Objekt (dh es überschreibt outer die Bindung)?


Die ECMAScript specs besagt, dass, wenn der Ausführungskontext für Funktionscode eingeben, wenn die «Anrufer thisArg zur Verfügung gestellt» entweder null oder undefined, dann wird this auf das globale Objekt gebunden.

Aber die folgenden:

var o = { 
    outer: function() { 
     var inner = function() { 
      console.log('caller is ' + arguments.callee.caller); 
     }; 
     inner(); 
    } 
} 

gibt das Objekt outer selbst:

caller is function() { 
    var inner = function() { 
     console.log('caller is ' + arguments.callee.caller); 
    }; 
    inner(); 
} 



Auf einer Seite, aber wahrscheinlich relevant, Anmerkung:
In strengen Modus die ersten Code-Snippet-Ausgaben undefined anstelle von Fenster.

+3

Es ist, weil, wie Sie anrufen 'Innen '-' inner(); '. Der Wert von 'this' wird durch die Art festgelegt, wie Sie die Funktion aufrufen. Wie auch immer, "innere" hat keine Beziehung zu "äußeren", es ist nur eine lokale Variable. Wenn Sie 'console.log (this);' innerhalb von 'extern' verwendet haben und es wie folgt aufgerufen haben: 'var a = o.outer; a(); ', Sie bekommen' Fenster'. Sie mögen denken, dass es Unsinn ist, aber es ist so konzipiert - Sie müssen lernen, wie man es richtig verwendet. – Ian

+0

"Die ECMAScript-Spezifikationen geben an, dass beim Eingeben des Ausführungskontexts für den Funktionscode, wenn der von diesem Aufrufer bereitgestellte thisArg entweder null oder nicht definiert ist, dieser an das globale Objekt gebunden ist." - Hast du deine eigene Frage nicht beantwortet? 'inner()' spezifiziert nicht thisArg. –

+0

@Ian so macht der Umfang, in dem der Anruf getätigt wird, überhaupt keine Rolle? –

Antwort

3

So funktioniert die Sprache.

Jede Zeit, die eine Funktion aufgerufen wird, this wird zurückgesetzt. In einer verschachtelten (inneren) Funktion erbt es den Wert aus dem umschließenden Bereich nicht wie andere (explizit deklarierte) Variablen.

standardmäßigthis wird window eingestellt werden, es sei denn, die Funktion aufgerufen als:

  • myObj.func(arg1, ...) oder
  • func.call(myObj, arg1, ...) oder
  • func.apply(myObj, [arg1, ...])

in welchem ​​Fall this wird gleich myObj

Eine Funktion eine andere Möglichkeit genannt, auch wenn es ursprünglich als eine Eigenschaft eines Objekts definiert wurde (d.h. var func = myObj.func; func() wird window verwenden.

Es gibt auch eine Nutzenfunktion .bind genannt, die eine Funktionsreferenz so hüllt, dass Sie einen bestimmten Wert bereitstellen kann, die immer als this verwendet werden:

var myFunc = myObj.func;    // obtain reference to func 
var bound = myFunc.bind(someOtherObj); // bind it to "someOtherObj" 

bound();        // this === someOtherObj 
bound.call(myObj)      // this still === someOtherObj 
6

Dies ist, weil this festgelegt ist, wenn die Funktion ausgeführt wird, nicht wenn es definiert ist.

Zum Beispiel:

var o = { 
    func: function(){ 
     console.log(this); 
    } 
}; 

Wenn Sie o.func() nennen, Sie tun dies im Rahmen o, so funktioniert es wie erwartet.

Lassen Sie uns jetzt sagen, Sie tun dies:

var f = o.func; 
f(); 

Dies wird nicht wie erwartet funktionieren. Dies liegt daran, dass beim Aufruf von f() kein Kontext mit diesem verknüpft ist. Daher wird thiswindow.

Sie können dies beheben, indem Sie .call verwenden, um den Wert this zu ändern.

var f = o.func; 
f.call(o); // sets `this` to `o` when calling it