Segue un estratto da Closure: The Definitive Guide di Michael Bolin . Potrebbe sembrare un po 'lungo, ma è saturo di molte intuizioni. Da "Appendice B. Concetti JavaScript spesso fraintesi":
Cosa si this
riferisce a quando viene chiamata una funzione
Quando si chiama una funzione del modulo foo.bar.baz()
, l'oggetto foo.bar
viene indicato come destinatario. Quando viene chiamata la funzione, è il ricevitore che viene utilizzato come valore per 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);
Se non è presente un destinatario esplicito quando viene chiamata una funzione, l'oggetto globale diventa il destinatario. Come spiegato in "goog.global" a pagina 47, window è l'oggetto globale quando JavaScript viene eseguito in un browser web. Questo porta ad alcuni comportamenti sorprendenti:
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
Anche se obj.addValues
ef
si riferiscono alla stessa funzione, si comportano in modo diverso quando chiamato perché il valore del ricevitore è diverso in ciascuna chiamata. Per questo motivo, quando si chiama una funzione a cui si fa riferimento this
, è importante assicurarsi che this
abbia il valore corretto quando viene chiamata. Per essere chiari, se this
non si facesse riferimento nel corpo della funzione, il comportamento f(20)
e obj.addValues(20)
sarebbe lo stesso.
Poiché le funzioni sono oggetti di prima classe in JavaScript, possono avere i propri metodi. Tutte le funzioni hanno i metodicall()
e apply()
che rendono possibile ridefinire il ricevitore (cioè l'oggetto a cui si this
fa riferimento) quando si chiama la funzione. Le firme del metodo sono le seguenti:
/**
* @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;
Si noti che l'unica differenza tra call()
eapply()
è che call()
riceve i parametri della funzione come singoli argomenti, mentre apply()
li riceve come un singolo array:
// 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]);
Le seguenti chiamate sono equivalenti, come f
e obj.addValues
riferiscono alla stessa funzione:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
Tuttavia, poiché nessuno dei due call()
né apply()
utilizza né il valore del proprio ricevitore per sostituire l'argomento del ricevitore quando non è specificato, non funzionerà quanto segue:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
Il valore di this
non può mai essere null
o undefined
quando viene chiamata una funzione. quandonull
o undefined
viene fornito come destinatario a call()
o apply()
, l'oggetto globale viene invece utilizzato come valore per il destinatario. Pertanto, il codice precedente ha lo stesso effetto collaterale indesiderato dell'aggiunta di una proprietà denominata value
nell'oggetto globale.
Può essere utile pensare a una funzione come a non avere conoscenza della variabile a cui è assegnata. Questo aiuta a rafforzare l'idea che il valore di questo sarà associato quando viene chiamata la funzione piuttosto che quando viene definita.
Fine dell'estratto.
a
in apply per array di args ec
in call per colonne di args.