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 this
verrebbe 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, this
faresti 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, this
non farebbe più riferimento alla variabile globale in nessuno degli ambienti. Questo viene fatto per evitare confusioni in modalità rigorosa. this
sarebbe, 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 forEach
e slice
, dovresti già sapere che la this
variabile in quel caso si riferisce a quella Object
su cui hai chiamato quella funzione (Nota che in javascript, quasi tutto è un Object
, compresi se Array
e Function
s). 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 Object
contiene una proprietà che contiene un Function
, la proprietà viene chiamata metodo. Questo metodo, quando chiamato, avrà sempre la sua this
variabile impostata Object
sull'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 this
non 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 new
parola 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 new
parola chiave.
- Chiamare la funzione con la
new
parola chiave inizializzerebbe immediatamente un Object
tipo Person
.
- Il costruttore di questo
Object
ha il suo costruttore impostato su Person
. Inoltre, si noti che typeof awal
sarebbe Object
solo di ritorno .
- A questo nuovo
Object
verrebbe assegnato il prototipo di Person.prototype
. Ciò significa che qualsiasi metodo o proprietà nel Person
prototipo sarebbe disponibile per tutte le istanze di Person
, incluso awal
.
- La funzione
Person
stessa è ora invocata; this
essendo 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 constructor
funzioni effettive . Sono solo normali funzioni e new
possono essere utilizzate su qualsiasi funzione. È solo che li usiamo come tali, e quindi li chiamiamo solo come tali.
Chiamata di funzioni su Funzioni: call
eapply
Quindi sì, poiché anche function
s 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 Function
e due dei suoi numerosi metodi sono call
e apply
, ed entrambi possono essere usati per manipolare il valore della this
funzione 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 this
la funzione foo
come riferimento a thisArg
. Tutti gli altri parametri passati a call
vengono passati alla funzione foo
come argomenti.
Quindi il codice sopra accederà {myObj: "is cool"}, [1, 2, 3]
alla console. Modo abbastanza carino per cambiare il valore di this
in qualsiasi funzione.
apply
equivale quasi ad call
accettare che accetta solo due parametri: thisArg
e un array che contiene gli argomenti da passare alla funzione. Quindi la call
chiamata sopra può essere tradotta in apply
questo modo:
foo.apply(thisArg, [1,2,3])
Si noti che call
e apply
può sovrascrivere il valore di this
set tramite invocazione del metodo punto di cui abbiamo discusso nel secondo punto. Abbastanza semplice :)
Presentando .... bind
!
bind
è un fratello di call
e apply
. È anche un metodo ereditato da tutte le funzioni del Function
costruttore globale in Javascript. La differenza tra bind
e call
/ apply
è che entrambi call
e apply
invocheranno effettivamente la funzione. bind
d'altra parte, restituisce una nuova funzione con thisArg
e arguments
preimpostato. 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 call
e apply
, bind
inoltre , supererà il valore di this
set tramite l'invocazione del metodo punto.
Si noti inoltre che nessuna di queste tre funzioni modifica la funzione originale. call
e apply
restituirebbe il valore da funzioni appena costruite mentre bind
restituirà la funzione appena costruita stessa, pronta per essere chiamata.
Roba extra, copia questo
A volte, non ti piace il fatto che this
cambi 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 è this
cambiato con l'ambito nidificato, ma volevamo il valore di this
dall'ambito originale. Così abbiamo 'copiato' this
al that
e abbiamo usato la copia anziché this
. Intelligente, eh?
Indice:
- Cosa è trattenuto
this
di default?
- Cosa succede se chiamiamo la funzione come metodo con notazione Object-dot?
- E se usiamo la
new
parola chiave?
- Come manipoliamo
this
con call
e apply
?
- Usando
bind
.
- Copia
this
per risolvere i problemi relativi all'ambito nidificato.