Es folgt ein Auszug aus Closure: The Definitive Guide von Michael Bolin . Es mag etwas lang aussehen, aber es ist voller Einsichten. Aus "Anhang B. Häufig missverstandene JavaScript-Konzepte":
Worauf this
bezieht sich, wenn eine Funktion aufgerufen wird ?
Beim Aufrufen einer Funktion des Formulars foo.bar.baz()
wird das Objekt foo.bar
als Empfänger bezeichnet. Wenn die Funktion aufgerufen wird, wird der Empfänger als Wert für Folgendes verwendet this
:
var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
for (var i = 0; i < arguments.length; i++) {
this.value += arguments[i];
}
return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);
Wenn es beim Aufruf einer Funktion keinen expliziten Empfänger gibt, wird das globale Objekt zum Empfänger. Wie unter "goog.global" auf Seite 47 erläutert, ist window das globale Objekt, wenn JavaScript in einem Webbrowser ausgeführt wird. Dies führt zu überraschendem Verhalten:
var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN
Obwohl obj.addValues
und f
beziehen sich auf dieselbe Funktion, verhalten sie sich beim Aufruf unterschiedlich, da der Wert des Empfängers bei jedem Anruf unterschiedlich ist. Aus diesem Grund ist es beim Aufrufen einer Funktion, auf die this
verwiesen wird, wichtig sicherzustellen, dass sie beim Aufrufen this
den richtigen Wert hat. Um klar zu sein, wenn this
im Funktionskörper nicht darauf verwiesen würde, wäre das Verhalten von f(20)
und obj.addValues(20)
dasselbe.
Da Funktionen in JavaScript erstklassige Objekte sind, können sie ihre eigenen Methoden haben. Alle Funktionen haben die Methoden call()
und apply()
die es ermöglichen , den Empfänger neu zu definieren (dh das Objekt , das this
sich bezieht) , wenn die Funktion aufgerufen wird . Die Methodensignaturen lauten wie folgt:
/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;
Beachten Sie, dass der einzige Unterschied zwischen call()
und darin apply()
besteht, dass call()
die Funktionsparameter als einzelne Argumente apply()
empfangen werden , während sie als einzelnes Array empfangen werden:
// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);
Die folgenden Aufrufe sind äquivalent f
und obj.addValues
beziehen sich auf dieselbe Funktion:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
Da jedoch weder call()
noch apply()
verwendet den Wert des eigenen Empfängers Ersatz für den Empfänger Argument , wenn es nicht spezifiziert, die folgende nicht funktionieren:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
Der Wert von this
kann niemals sein null
oder undefined
wenn eine Funktion aufgerufen wird. Wenn null
oder undefined
als Empfänger an call()
oder geliefert apply()
wird, wird stattdessen das globale Objekt als Wert für den Empfänger verwendet. Daher hat der vorherige Code den gleichen unerwünschten Nebeneffekt beim Hinzufügen einer Eigenschaft mit dem Namen value
zum globalen Objekt.
Es kann hilfreich sein, sich eine Funktion so vorzustellen, dass sie die Variable, der sie zugewiesen ist, nicht kennt. Dies hilft dabei, die Idee zu bekräftigen, dass der Wert davon gebunden wird, wenn die Funktion aufgerufen wird, anstatt wenn sie definiert wird.
Ende des Extrakts.
a
in gelten für Array von Argumenten undc
in Aufruf für Spalten von Argumenten.