Javascript del this
Richiamo semplice funzione
Considera la seguente funzione:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Si noti che lo stiamo eseguendo in modalità normale, ovvero la modalità rigorosa non viene utilizzata.
Durante l'esecuzione in un browser, il valore di thisverrebbe registrato come window. Questo perché windowè la variabile globale nell'ambito di un browser web.
Se esegui questo stesso pezzo di codice in un ambiente come node.js, thisfaresti riferimento alla variabile globale nella tua app.
Ora, se lo eseguiamo in modalità rigorosa aggiungendo l'istruzione "use strict";all'inizio della dichiarazione di funzione, thisnon farebbe più riferimento alla variabile globale in nessuno degli ambienti. Questo viene fatto per evitare confusioni in modalità rigorosa. thissarebbe, in questo caso undefined, registrare , perché è quello che è, non è definito.
Nei seguenti casi, vedremmo come manipolare il valore di this.
Chiamare una funzione su un oggetto
Esistono diversi modi per farlo. Se hai chiamato metodi nativi in Javascript come forEache slice, dovresti già sapere che la thisvariabile in quel caso si riferisce a quella Objectsu cui hai chiamato quella funzione (Nota che in javascript, quasi tutto è un Object, compresi se Arraye Functions). Prendi ad esempio il seguente codice.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
Se un Objectcontiene una proprietà che contiene un Function, la proprietà viene chiamata metodo. Questo metodo, quando chiamato, avrà sempre la sua thisvariabile impostata Objectsull'associato. Questo è vero sia per le modalità rigide che non rigide.
Se un metodo viene memorizzato (o meglio, copiato) in un'altra variabile, il riferimento a thisnon viene più conservato nella nuova variabile. Per esempio:
// continuing with the previous code snippet
var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
Considerando uno scenario più comunemente pratico:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
La newparola chiave
Considera una funzione di costruzione in Javascript:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
Come funziona? Bene, vediamo cosa succede quando usiamo la newparola chiave.
- Chiamare la funzione con la
newparola chiave inizializzerebbe immediatamente un Objecttipo Person.
- Il costruttore di questo
Objectha il suo costruttore impostato su Person. Inoltre, si noti che typeof awalsarebbe Objectsolo di ritorno .
- A questo nuovo
Objectverrebbe assegnato il prototipo di Person.prototype. Ciò significa che qualsiasi metodo o proprietà nel Personprototipo sarebbe disponibile per tutte le istanze di Person, incluso awal.
- La funzione
Personstessa è ora invocata; thisessendo un riferimento all'oggetto di nuova costruzione awal.
Abbastanza semplice, eh?
Si noti che le specifiche ECMAScript ufficiali non indicano da nessuna parte che tali tipi di funzioni sono constructorfunzioni effettive . Sono solo normali funzioni e newpossono essere utilizzate su qualsiasi funzione. È solo che li usiamo come tali, e quindi li chiamiamo solo come tali.
Chiamata di funzioni su Funzioni: calleapply
Quindi sì, poiché anche functions sono Objects(e in effetti variabili di prima classe in Javascript), anche le funzioni hanno metodi che sono ... beh, funzioni stesse.
Tutte le funzioni ereditano dal globale Functione due dei suoi numerosi metodi sono calle apply, ed entrambi possono essere usati per manipolare il valore della thisfunzione su cui sono chiamati.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
Questo è un tipico esempio di utilizzo call. Praticamente prende il primo parametro e imposta thisla funzione foocome riferimento a thisArg. Tutti gli altri parametri passati a callvengono passati alla funzione foocome argomenti.
Quindi il codice sopra accederà {myObj: "is cool"}, [1, 2, 3]alla console. Modo abbastanza carino per cambiare il valore di thisin qualsiasi funzione.
applyequivale quasi ad callaccettare che accetta solo due parametri: thisArge un array che contiene gli argomenti da passare alla funzione. Quindi la callchiamata sopra può essere tradotta in applyquesto modo:
foo.apply(thisArg, [1,2,3])
Si noti che calle applypuò sovrascrivere il valore di thisset tramite invocazione del metodo punto di cui abbiamo discusso nel secondo punto. Abbastanza semplice :)
Presentando .... bind!
bindè un fratello di calle apply. È anche un metodo ereditato da tutte le funzioni del Functioncostruttore globale in Javascript. La differenza tra binde call/ applyè che entrambi calle applyinvocheranno effettivamente la funzione. bindd'altra parte, restituisce una nuova funzione con thisArge argumentspreimpostato. Facciamo un esempio per capire meglio questo:
function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
Vedi la differenza tra i tre? È sottile, ma sono usati in modo diverso. Like calle apply, bindinoltre , supererà il valore di thisset tramite l'invocazione del metodo punto.
Si noti inoltre che nessuna di queste tre funzioni modifica la funzione originale. calle applyrestituirebbe il valore da funzioni appena costruite mentre bindrestituirà la funzione appena costruita stessa, pronta per essere chiamata.
Roba extra, copia questo
A volte, non ti piace il fatto che thiscambi con l'ambito, in particolare l'ambito nidificato. Dai un'occhiata al seguente esempio.
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
Nel codice sopra, vediamo che il valore di è thiscambiato con l'ambito nidificato, ma volevamo il valore di thisdall'ambito originale. Così abbiamo 'copiato' thisal thate abbiamo usato la copia anziché this. Intelligente, eh?
Indice:
- Cosa è trattenuto
thisdi default?
- Cosa succede se chiamiamo la funzione come metodo con notazione Object-dot?
- E se usiamo la
newparola chiave?
- Come manipoliamo
thiscon calle apply?
- Usando
bind.
- Copia
thisper risolvere i problemi relativi all'ambito nidificato.