Cosa dovresti sapere this
this
(aka "il contesto") è una parola chiave speciale all'interno di ciascuna funzione e il suo valore dipende solo da come è stata chiamata la funzione, non da come / quando / dove è stata definita. Non è influenzato da ambiti lessicali come altre variabili (ad eccezione delle funzioni freccia, vedere di seguito). Ecco alcuni esempi:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Per saperne di più this
, dai un'occhiata alla documentazione MDN .
Come fare riferimento al corretto this
Non usare this
In realtà non si desidera accedere this
in particolare, ma l'oggetto a cui si riferisce . Ecco perché una soluzione semplice è semplicemente creare una nuova variabile che si riferisce anche a quell'oggetto. La variabile può avere qualsiasi nome, ma quelli comuni sono self
e that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Poiché self
è una variabile normale, obbedisce alle regole dell'ambito lessicale ed è accessibile all'interno del callback. Ciò ha anche il vantaggio di poter accedere al this
valore del callback stesso.
Set esplicito this
del callback - parte 1
Potrebbe sembrare che tu non abbia alcun controllo sul valore di this
perché il suo valore è impostato automaticamente, ma in realtà non è così.
Ogni funzione ha il metodo .bind
[docs] , che restituisce una nuova funzione this
associata a un valore. La funzione ha esattamente lo stesso comportamento di quella che hai chiamato .bind
, solo che è this
stata impostata da te. Indipendentemente da come o quando viene chiamata quella funzione, this
farà sempre riferimento al valore passato.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
In questo caso, associamo i callback this
al valore di MyConstructor
's this
.
Nota: quando si associa un contesto per jQuery, utilizzare invece jQuery.proxy
[docs] . La ragione per fare ciò è che non è necessario memorizzare il riferimento alla funzione quando si annulla un callback di un evento. jQuery lo gestisce internamente.
ECMAScript 6 introduce funzioni freccia , che possono essere pensate come funzioni lambda. Non hanno il loro this
legame. Invece, this
è cercato nell'ambito proprio come una normale variabile. Ciò significa che non devi chiamare .bind
. Non è l'unico comportamento speciale che hanno, fare riferimento alla documentazione MDN per ulteriori informazioni.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Set this
di callback - parte 2
Alcune funzioni / metodi che accettano i callback accettano anche un valore a cui this
dovrebbero fare riferimento i callback . Questo è fondamentalmente lo stesso che associarlo tu stesso, ma la funzione / metodo lo fa per te. Array#map
[docs] è un tale metodo. La sua firma è:
array.map(callback[, thisArg])
Il primo argomento è il callback e il secondo argomento è il valore a cui this
dovrebbe fare riferimento. Ecco un esempio inventato:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Nota: la possibilità o meno di trasmettere un valore this
è di solito menzionata nella documentazione di tale funzione / metodo. Ad esempio, il $.ajax
metodo [docs] di jQuery descrive un'opzione chiamata context
:
Questo oggetto verrà inserito nel contesto di tutti i callback relativi ad Ajax.
Problema comune: utilizzo dei metodi oggetto come callback / gestori di eventi
Un'altra manifestazione comune di questo problema è quando un metodo oggetto viene utilizzato come gestore di callback / evento. Le funzioni sono cittadini di prima classe in JavaScript e il termine "metodo" è solo un termine colloquiale per una funzione che è un valore di una proprietà dell'oggetto. Ma quella funzione non ha un collegamento specifico al suo oggetto "contenente".
Considera il seguente esempio:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
La funzione this.method
è assegnata come gestore eventi click, ma se si document.body
fa clic, il valore registrato sarà undefined
, perché all'interno del gestore eventi, si this
riferisce a document.body
, non all'istanza di Foo
.
Come già accennato all'inizio, ciò che si this
riferisce dipende da come viene chiamata la funzione , non da come viene definita .
Se il codice fosse simile al seguente, potrebbe essere più ovvio che la funzione non ha un riferimento implicito all'oggetto:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
La soluzione è la stessa di cui sopra: se disponibile, utilizzare .bind
per associare esplicitamente this
a un valore specifico
document.body.onclick = this.method.bind(this);
o chiama esplicitamente la funzione come "metodo" dell'oggetto, usando una funzione anonima come gestore di callback / evento e assegna l'oggetto ( this
) a un'altra variabile:
var self = this;
document.body.onclick = function() {
self.method();
};
o usa una funzione freccia:
document.body.onclick = () => this.method();