Funktionsaufrufe
Funktionen sind nur eine Art Objekt.
Alle Funktionsobjekte verfügen über Methoden zum Aufrufen und Anwenden , mit denen das aufgerufene Funktionsobjekt ausgeführt wird.
Beim Aufruf gibt das erste Argument für diese Methoden das Objekt an, auf das das this
Schlüsselwort während der Ausführung der Funktion verweist - wenn es null
oder undefined
das globale Objekt window
für verwendet wird this
.
Aufrufen einer Funktion ...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
... mit Klammern - foo()
- entspricht foo.call(undefined)
oder foo.apply(undefined)
, was praktisch dasselbe ist wie foo.call(window)
oder foo.apply(window)
.
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Zusätzliche Argumente, call
die als Argumente an den Funktionsaufruf übergeben werden sollen, während ein einzelnes zusätzliches Argument apply
die Argumente für den Funktionsaufruf als Array-ähnliches Objekt angeben kann.
Somit foo(1, 2, 3)
ist äquivalent zu foo.call(null, 1, 2, 3)
oder foo.apply(null, [1, 2, 3])
.
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
Wenn eine Funktion eine Eigenschaft eines Objekts ist ...
var obj =
{
whereAmI: "obj",
foo: foo
};
... der Zugriff auf einen Verweis auf die Funktion über das Objekt und der Aufruf mit Klammern - obj.foo()
- entspricht foo.call(obj)
oder foo.apply(obj)
.
Funktionen, die als Eigenschaften von Objekten gehalten werden, sind jedoch nicht an diese Objekte "gebunden". Wie Sie in der obj
obigen Definition sehen können , können Funktionen, da sie nur eine Art von Objekt sind, referenziert werden (und somit als Referenz auf einen Funktionsaufruf übergeben oder als Referenz von einem Funktionsaufruf zurückgegeben werden). Wenn ein Verweis auf eine Funktion übergeben wird, werden keine zusätzlichen Informationen darüber mitgeführt, woher er übergeben wurde. Aus diesem Grund geschieht Folgendes:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
Der Aufruf unserer Funktionsreferenz baz
bietet keinen Kontext für den Aufruf, ist also praktisch derselbe wie baz.call(undefined)
, führt also zu this
einer Referenzierung window
. Wenn wir baz
wissen wollen , dass es dazu gehört, obj
müssen wir diese Informationen irgendwie bereitstellen, wenn sie baz
aufgerufen werden. Hier kommt das erste Argument für call
oder apply
und Schließungen ins Spiel.
Zielfernrohrketten
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
Wenn eine Funktion ausgeführt wird, erstellt sie einen neuen Bereich und verweist auf einen beliebigen umschließenden Bereich. Wenn die anonyme Funktion im obigen Beispiel erstellt wird, verweist sie auf den Bereich, in dem sie erstellt wurde. Dies ist bind
der Bereich. Dies ist als "Verschluss" bekannt.
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
Wenn Sie versuchen, auf eine Variable zuzugreifen, wird diese "Bereichskette" durchlaufen, um eine Variable mit dem angegebenen Namen zu finden. Wenn der aktuelle Bereich die Variable nicht enthält, sehen Sie sich den nächsten Bereich in der Kette an und so weiter, bis Sie ihn erreichen der globale Umfang. Wenn die anonyme Funktion zurückgegeben wird und die bind
Ausführung abgeschlossen ist, hat die anonyme Funktion immer noch einen Verweis auf bind
den Gültigkeitsbereich, sodass bind
der Gültigkeitsbereich nicht "verschwindet".
Angesichts all der oben genannten Punkte sollten Sie nun in der Lage sein zu verstehen, wie der Gültigkeitsbereich im folgenden Beispiel funktioniert und warum die Technik zum Übergeben einer Funktion um "vorgebunden" mit einem bestimmten Wert this
funktioniert, wenn sie aufgerufen wird:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};