Come funziona la parola chiave "this"?


1309

Ho notato che non sembra esserci una chiara spiegazione di cosa sia la thisparola chiave e come sia correttamente (e erroneamente) utilizzata in JavaScript sul sito Stack Overflow.

Ho assistito ad un comportamento molto strano con esso e non sono riuscito a capire perché si è verificato.

Come thisfunziona e quando dovrebbe essere usato?


6
Ho trovato questo quando ho cercato su Google
Wai Wong,



1
La panoramica di MDN non è affatto male ... developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…
dat

2
Una spiegazione interessante della thisparola chiave: rainsoft.io/gentle-explanation-of-this-in-javascript
Dmitri Pavlutin

Risposte:


1351

Vi consiglio di leggere Mike occidentale articolo s' Ambito di applicazione in JavaScript ( specchio ) prima. È un'introduzione eccellente e amichevole ai concetti thise alle catene di portata in JavaScript.

Una volta che inizi ad abituarti this, le regole sono in realtà piuttosto semplici. Lo standard ECMAScript 5.1 definisce this:

§11.1.1 La thisparola chiave

La thisparola chiave restituisce il valore di ThisBinding del contesto di esecuzione corrente

ThisBinding è qualcosa che l'interprete JavaScript mantiene mentre valuta il codice JavaScript, come un registro CPU speciale che contiene un riferimento a un oggetto. L'interprete aggiorna ThisBinding ogni volta che stabilisce un contesto di esecuzione in uno dei soli tre casi diversi:

1. Contesto di esecuzione globale iniziale

Questo è il caso del codice JavaScript che viene valutato al livello più alto, ad es. Direttamente all'interno di un <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

Quando si valuta il codice nel contesto di esecuzione globale iniziale, ThisBinding è impostato sull'oggetto globale, window( §10.4.1.1 ).

Immissione del codice di valutazione

  • ... con una chiamata diretta a eval() ThisBinding rimane invariato; ha lo stesso valore di ThisBinding del contesto di esecuzione della chiamata ( §10.4.2 (2) (a)).

  • ... se non tramite una chiamata diretta a eval()
    ThisBinding è impostato sull'oggetto globale come se si eseguisse nel contesto di esecuzione globale iniziale ( §10.4.2 (1)).

§15.1.2.1.1 definisce a cosa serve una chiamata diretta eval(). Fondamentalmente, eval(...)è una chiamata diretta mentre qualcosa di simile (0, eval)(...)o var indirectEval = eval; indirectEval(...);è una chiamata indiretta a eval(). Vedi la risposta di chuckj a (1, eval) ('this') vs eval ('this') in JavaScript? e l'ECMA-262-5 di Dmitry Soshnikov in dettaglio. Capitolo 2. Modalità rigorosa. per quando potresti usare una eval()chiamata indiretta .

Immissione del codice funzione

Ciò si verifica quando si chiama una funzione. Se una funzione viene chiamata su un oggetto, come in obj.myMethod()o l'equivalente obj["myMethod"](), ThisBinding viene impostato sull'oggetto ( objnell'esempio; §13.2.1 ). Nella maggior parte degli altri casi, ThisBinding è impostato sull'oggetto globale ( §10.4.3 ).

Il motivo per cui si scrive "nella maggior parte degli altri casi" è perché ci sono otto funzioni integrate ECMAScript 5 che consentono a ThisBinding di essere specificato nell'elenco degli argomenti. Queste funzioni speciali prendono un cosiddetto thisArgche diventa ThisBinding quando chiama la funzione ( §10.4.3 ).

Queste speciali funzioni integrate sono:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Nel caso delle Function.prototypefunzioni, vengono chiamate su un oggetto funzione, ma anziché impostare ThisBinding sull'oggetto funzione, ThisBinding è impostato su thisArg.

Nel caso delle Array.prototypefunzioni, il dato callbackfnviene chiamato in un contesto di esecuzione in cui ThisBinding è impostato su thisArgse fornito; altrimenti, per l'oggetto globale.

Queste sono le regole per JavaScript semplice. Quando inizi a utilizzare le librerie JavaScript (ad esempio jQuery), potresti scoprire che alcune funzioni della libreria modificano il valore di this. Gli sviluppatori di queste librerie JavaScript lo fanno perché tende a supportare i casi d'uso più comuni e gli utenti della libreria in genere trovano questo comportamento più conveniente. Quando si passano le funzioni di callback facendo riferimento thisalle funzioni della libreria, è necessario fare riferimento alla documentazione per eventuali garanzie su quale sia il valore di thisquando viene chiamata la funzione.

Se ti stai chiedendo come una libreria JavaScript manipola il valore di this, la libreria sta semplicemente usando una delle funzioni JavaScript integrate che accetta a thisArg. Anche tu puoi scrivere la tua funzione assumendo una funzione di callback e thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

C'è un caso speciale che non ho ancora menzionato. Quando si costruisce un nuovo oggetto tramite l' newoperatore, l'interprete JavaScript crea un nuovo oggetto vuoto, imposta alcune proprietà interne e quindi chiama la funzione di costruzione sul nuovo oggetto. Pertanto, quando una funzione viene chiamata in un contesto di costruzione, il valore di thisè il nuovo oggetto creato dall'interprete:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Funzioni freccia

Le funzioni freccia (introdotte in ECMA6) modificano l'ambito di this. Vedi la domanda canonica esistente, Funzione freccia vs dichiarazione di funzione / espressioni: sono equivalenti / scambiabili? per maggiori informazioni. Ma in breve:

Le funzioni freccia non hanno il loro this.... legame. Invece, tali identificatori vengono risolti nell'ambito lessicale come qualsiasi altra variabile. Ciò significa che all'interno di una funzione freccia, this... fare riferimento ai valori thisnell'ambiente in cui è definita la funzione freccia.

Solo per divertimento, prova la tua comprensione con alcuni esempi

Per rivelare le risposte, passa con il mouse sopra le caselle grigio chiaro.

  1. Qual è il valore di thisalla linea contrassegnata? Perché?

    window - La linea contrassegnata viene valutata nel contesto di esecuzione globale iniziale.

    if (true) {
        // What is `this` here?
    }
  2. Qual è il valore di thissulla linea contrassegnata quando obj.staticFunction()viene eseguito? Perché?

    obj - Quando si chiama una funzione su un oggetto, ThisBinding è impostato sull'oggetto.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      

  3. Qual è il valore di thisalla linea contrassegnata? Perché?

    window

    In questo esempio, l'interprete JavaScript inserisce il codice funzione, ma poiché myFun/ obj.myMethodnon viene chiamato su un oggetto, ThisBinding è impostato su window.

    Questo è diverso da Python, in cui l'accesso a un metodo ( obj.myMethod) crea un oggetto metodo associato .

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      

  4. Qual è il valore di thisalla linea contrassegnata? Perché?

    window

    Questo è stato difficile. Quando si valuta il codice di valutazione, thisè obj. Tuttavia, nel codice di myFunvalutazione , non viene chiamato su un oggetto, quindi ThisBinding è impostato su windowper la chiamata.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
  5. Qual è il valore di thisalla linea contrassegnata? Perché?

    obj

    La linea myFun.call(obj);sta invocando la speciale funzione integrata Function.prototype.call(), che accetta thisArgcome primo argomento.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      


6
@Ali: sono riferimenti a sezioni dell'edizione 5.1 della norma ECMAScript, ECMA-262 . Li fornisco in modo che tu possa leggere lo Standard per i dettagli tecnici se lo desideri.
Daniel Trebbien,

1
Penso che @supertonsky abbia ragione su # 2 - se myFun () viene chiamato dall'ambito globale, e non come metodo sull'oggetto, "questo" sarà l'oggetto globale, quindi il fraseggio della domanda è importante. btw - Mi piace molto l'idea di usare il mouseover per ottenere la risposta a qualcosa del genere.
user655489

2
Ma jsfiddle.net/H4LYm/2 mostra che l' setTimeoutesempio ha un thisdi window(global).
Kevin Meredith,

2
proveniente da Python si immaginerebbe i livelli di frustrazione che ho avuto quando mi sono imbattuto nel terzo esempio .. smh
Marius Mucenicu,

1
Questa risposta dovrebbe probabilmente essere aggiornata per riflettere la realtà ES2020, anche se i cambiamenti sono solo terminologici.
Ben Aston,

156

La thisparola chiave si comporta diversamente in JavaScript rispetto ad altre lingue. Nei linguaggi orientati agli oggetti, la thisparola chiave si riferisce all'istanza corrente della classe. In JavaScript il valore di thisè determinato dal contesto di invocazione di function ( context.function()) e da dove viene chiamato.

1. Se utilizzato in un contesto globale

Quando lo si utilizza thisnel contesto globale, è associato all'oggetto globale ( windownel browser)

document.write(this);  //[object Window]

Quando si utilizza thisall'interno di una funzione definita nel contesto globale, thisviene comunque associato all'oggetto globale poiché la funzione viene effettivamente trasformata in un metodo di contesto globale.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Sopra f1è realizzato un metodo di oggetto globale. Quindi possiamo anche chiamarlo su windowoggetto come segue:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Se utilizzato nel metodo dell'oggetto

Quando si utilizza la thisparola chiave all'interno di un metodo oggetto, thisviene associato all'oggetto che racchiude "immediato".

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Sopra ho messo la parola immediata tra virgolette doppie. È per sottolineare che se annidate l'oggetto all'interno di un altro oggetto, allora thisè associato al genitore immediato.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Anche se si aggiunge esplicitamente la funzione all'oggetto come metodo, segue comunque le regole precedenti, ovvero thispunta ancora all'oggetto padre immediato.

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. Quando si richiama la funzione senza contesto

Quando si utilizza la thisfunzione interna che viene invocata senza alcun contesto (ovvero non su alcun oggetto), viene associata all'oggetto globale ( windownel browser) (anche se la funzione è definita all'interno dell'oggetto).

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Provando tutto con le funzioni

Possiamo provare anche i punti sopra con funzioni. Tuttavia ci sono alcune differenze.

  • Sopra abbiamo aggiunto membri agli oggetti usando la notazione letterale dell'oggetto. È possibile aggiungere membri alle funzioni utilizzando this. per specificarli.
  • La notazione letterale dell'oggetto crea un'istanza dell'oggetto che possiamo usare immediatamente. Con la funzione potremmo dover prima creare la sua istanza usando l' newoperatore.
  • Anche in un approccio letterale a oggetti, possiamo aggiungere esplicitamente membri a oggetti già definiti usando l'operatore punto. Questo viene aggiunto solo all'istanza specifica. Tuttavia, ho aggiunto una variabile al prototipo della funzione in modo che si rifletta in tutte le istanze della funzione.

Di seguito ho provato tutte le cose che abbiamo fatto con Object e thissopra, ma creando prima la funzione invece di scrivere direttamente un oggetto.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. Se utilizzato all'interno della funzione di costruzione .

Quando la funzione viene utilizzata come costruttore (ovvero quando viene chiamata con la newparola chiave), thisall'interno del corpo della funzione punta al nuovo oggetto in costruzione.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. Se utilizzato all'interno della funzione definita sulla catena di prototipi

Se il metodo si trova nella catena di prototipi di un oggetto, thisall'interno di tale metodo si intende l'oggetto su cui è stato chiamato il metodo, come se il metodo fosse definito sull'oggetto.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Funzioni interne call (), apply () e bind ()

  • Tutti questi metodi sono definiti su Function.prototype.
  • Questi metodi consentono di scrivere una funzione una volta e invocarla in un contesto diverso. In altre parole, consentono di specificare il valore di thiscui verrà utilizzato durante l'esecuzione della funzione. Prendono anche tutti i parametri da passare alla funzione originale quando viene invocata.
  • fun.apply(obj1 [, argsArray])Imposta obj1come valore di thisinside fun()e chiama gli fun()elementi di passaggio argsArraycome suoi argomenti.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Imposta obj1come valore di thisinside fun()e chiama le chiamate fun()passando arg1, arg2, arg3, ...come argomenti.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Restituisce il riferimento alla funzione funcon thislimite di divertimento interno obj1e parametri di funlimite ai parametri specificati arg1, arg2, arg3,....
  • Ormai la differenza tra apply, calle binddeve essere diventato evidente. applyconsente di specificare gli argomenti per funzionare come oggetto array-like, ovvero un oggetto con una lengthproprietà numerica e corrispondenti proprietà intere non negative. Considerando che callconsente di specificare direttamente gli argomenti per la funzione. Entrambi applye callinvoca immediatamente la funzione nel contesto specificato e con gli argomenti specificati. D'altra parte, bindrestituisce semplicemente la funzione associata al thisvalore specificato e agli argomenti. Possiamo acquisire il riferimento a questa funzione restituita assegnandolo a una variabile e successivamente possiamo chiamarlo in qualsiasi momento.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. thisgestori di eventi interni

  • Quando si assegna la funzione direttamente ai gestori di eventi di un elemento, l'uso della thisfunzione di gestione degli eventi direttamente all'interno si riferisce all'elemento corrispondente. Tale assegnazione diretta delle funzioni può essere eseguita utilizzando il addeventListenermetodo o attraverso i metodi tradizionali di registrazione degli eventi come onclick.
  • Allo stesso modo, quando si utilizza thisdirettamente all'interno della proprietà dell'evento (come <button onclick="...this..." >) dell'elemento, si riferisce all'elemento.
  • Tuttavia, l'uso thisindiretto tramite l'altra funzione chiamata all'interno della funzione di gestione degli eventi o la proprietà dell'evento si risolve nell'oggetto globale window.
  • Lo stesso comportamento sopra riportato si ottiene quando associamo la funzione al gestore eventi utilizzando il metodo del modello Registrazione eventi di Microsoft attachEvent. Invece di assegnare la funzione al gestore eventi (e quindi di creare il metodo di funzione dell'elemento), chiama la funzione sull'evento (chiamandola effettivamente nel contesto globale).

Consiglio di provare meglio questo in JSFiddle .

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

8. thisin funzione freccia ES6

In una funzione freccia, thissi comporterà come variabili comuni: sarà ereditato dal suo ambito lessicale. La funzione this, in cui è definita la funzione freccia, sarà la funzione freccia this.

Quindi, questo è lo stesso comportamento di:

(function(){}).bind(this)

Vedi il seguente codice:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 

"Quando lo usi all'interno di una funzione definita nel contesto globale, questo è ancora associato all'oggetto globale poiché la funzione è effettivamente trasformata in un metodo di contesto globale." non è corretto. questo è impostato dal modo in cui una funzione viene chiamata o dal bind , non da dove è definita. Chiamare qualsiasi funzione senza un riferimento di base ( "contesto") per impostazione predefinita questo l'oggetto globale o rimanere indefinito in modalità rigorosa.
RobG

@RobG hmm può essere, ma l'ho trovato su MDN : in questo caso, il valore di thisnon è impostato dalla chiamata. Poiché il codice non è in modalità rigorosa, il valore di thisdeve essere sempre un oggetto, quindi viene impostato per impostazione predefinita sull'oggetto globale. Ed in effetti è per questo che pensavo di poter effettuare chiamate direttamente window.f1(), quindi significa che f1()è già collegato windowall'oggetto, intendo prima dell'invocazione. Sto sbagliando?
Mahesha999,

Stavo commentando (forse non chiaramente) il tuo collegamento dell'impostazione di questo con "la funzione è in realtà un metodo del contesto globale", come se fosse una specie di chiamata window.fn, che non lo è. questo valore predefinito all'oggetto globale perché nessun riferimento di base è stato usato nella chiamata, non a causa di cui è definita la funzione (quindi questo è ancora impostato da come la funzione è stata chiamata). Se esplicitamente chiami usando window.fn, allora si sta impostando questo a finestra . Stesso risultato, diverso modo di procedere. :-)
RobG

"sopra ho messo la parola immediata ..." no non l'hai fatto. Puoi per favore rivedere questo in modo che l'errore sia corretto? Sembra semantico alla risposta e quindi non posso continuare a leggere fino a quando l'errore non viene corretto per paura di imparare qualcosa di errato.
TylerH,

@TylerH fai Ctrl + F in questa pagina nel tuo browser per trovare la stringa "immediata" (comprese le doppie virgolette) Penso che sia lì se ti sto capendo male
Mahesha999

64

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.

  1. Chiamare la funzione con la newparola chiave inizializzerebbe immediatamente un Objecttipo Person.
  2. Il costruttore di questo Objectha il suo costruttore impostato su Person. Inoltre, si noti che typeof awalsarebbe Objectsolo di ritorno .
  3. 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.
  4. 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:

  1. Cosa è trattenuto thisdi default?
  2. Cosa succede se chiamiamo la funzione come metodo con notazione Object-dot?
  3. E se usiamo la newparola chiave?
  4. Come manipoliamo thiscon calle apply?
  5. Usando bind.
  6. Copia thisper risolvere i problemi relativi all'ambito nidificato.

47

"questo" riguarda tutto l'ambito. Ogni funzione ha il suo ambito e, poiché tutto in JS è un oggetto, anche una funzione può memorizzare alcuni valori in se stessa usando "this". OOP 101 insegna che "this" è applicabile solo alle istanze di un oggetto. Pertanto, ogni volta che viene eseguita una funzione, una nuova "istanza" di quella funzione ha un nuovo significato di "questo".

Molte persone si confondono quando provano a usare "questo" all'interno di funzioni di chiusura anonime come:

(funzione (valore) {
    this.value = value;
    $ ('. Alcuni elementi). Each (function (elt) {
        elt.innerHTML = this.value; // Uh Oh!! forse indefinito
    });
}) (2);

Quindi qui, all'interno di ogni (), "this" non contiene il "valore" che ti aspetti (da

this.value = value;
Oltre a questo). Quindi, per superare questo problema (nessun gioco di parole previsto), uno sviluppatore potrebbe:

(funzione (valore) {
    var self = this; // piccolo cambiamento
    self.value = value;
    $ ('. Alcuni elementi). Each (function (elt) {
        elt.innerHTML = self.value; // phew !! == 2
    });
}) (2);

Provalo; inizierai ad apprezzare questo schema di programmazione


6
"Tutto in JS è un oggetto" non è vero, JavaScript ha anche valori primitivi, vedi bclary.com/2004/11/07/#a-4.3.2
Marcel Korpel,

6
I valori primitivi sembrano avere alcuni metodi su se stessi, come String # substring (), Number # toString (), ecc. Quindi, forse non con la stessa nomenclatura di quell'articolo, si comportano davvero come se fossero oggetti (sono tutti prototipati, ovvero String # substring () è in realtà: String.prototype.substring = function () {...}). Per favore correggimi se sbaglio.
Arunjitsingh,

12
La thisparola chiave non ha nulla a che fare con l'ambito. Inoltre, ha un significato anche nelle funzioni che non sono proprietà degli oggetti.
Bergi,

1
@ arunjitsingh: ci sono due scuole di pensiero su questo. Mi piace quello che dice " tutto è un oggetto, ma alcuni possono essere rappresentati dai primitivi per comodità ". ;-)
RobG

9
thisnon riguarda TUTTO l'ambito. Riguarda TUTTO il contesto di esecuzione, che non è la stessa cosa dell'ambito. JavaScript ha un ambito lessicale (il che significa che l'ambito è determinato dalla posizione del codice), ma thisè determinato da come viene invocata la funzione che lo contiene, non da dove si trova.
Scott Marcus,

16

Da quando questa discussione è cresciuta, ho raccolto alcuni punti per i lettori che non conoscono l' thisargomento.

Come viene thisdeterminato il valore ?

Usiamo questo simile al modo in cui usiamo i pronomi in linguaggi naturali come l'inglese: “John è in esecuzione veloce perché si sta cercando di prendere il treno.” Invece avremmo potuto scrivere "... John sta cercando di prendere il treno".

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this non viene assegnato un valore finché un oggetto non invoca la funzione in cui è definito. Nell'ambito globale, tutte le variabili e funzioni globali sono definite windowsull'oggetto. Pertanto, thisin una funzione globale si riferisce (e ha il valore di) l' windowoggetto globale .

Quando use strict, thisnelle funzioni globali e anonime che non sono associate a nessun oggetto, ha un valore di undefined.

La thisparola chiave viene fraintesa quando: 1) prendiamo in prestito un metodo che utilizza this, 2) assegniamo un metodo che utilizzathis a una variabile, 3) una funzione che utilizza thisviene passata come funzione di callback e 4) thisviene utilizzata all'interno di una chiusura - una funzione interiore. (2)

tavolo

Cosa riserva il futuro

Definito in ECMA Script 6 , le funzioni freccia adottano l' thisassociazione dall'ambito racchiuso (funzione o globale).

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Mentre le funzioni freccia offrono un'alternativa all'utilizzo bind(), è importante notare che essenzialmente disabilitano il tradizionalethis meccanismo a favore di un ambito lessicale più ampiamente compreso. (1)


Riferimenti:

  1. this & Object Prototypes , di Kyle Simpson. © 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Angus Croll - http://goo.gl/Z2RacU

16

thisin JavaScript si riferisce sempre al "proprietario" della funzione che viene eseguita .

Se non viene definito alcun proprietario esplicito, viene fatto riferimento al primo proprietario, l'oggetto finestra.

Quindi se lo facessi

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

thisfarebbe riferimento all'elemento element. Ma fai attenzione, molte persone commettono questo errore.

<element onclick="someKindOfFunction()">

In quest'ultimo caso, fai semplicemente riferimento alla funzione, non la passi all'elemento. Pertanto, thisfarà riferimento all'oggetto finestra.


15

Ogni contesto di esecuzione in JavaScript ha questo parametro impostato da:

  1. Come viene chiamata la funzione (incluso come metodo oggetto, uso di chiamata e applicazione , uso di nuovo )
  2. L'uso del legame
  3. Lessicamente per le funzioni freccia (adottano questo del loro contesto di esecuzione esterno)
  4. Se il codice è in modalità rigorosa o non rigorosa
  5. Se il codice è stato invocato utilizzando eval

È possibile impostare il valore di questo utilizzando func.call, func.applyo func.bind.

Per impostazione predefinita, e ciò che confonde la maggior parte dei principianti, quando un listener viene chiamato dopo che un evento è stato generato su un elemento DOM, questo valore della funzione è l'elemento DOM.

jQuery rende questo banale cambiare con jQuery.proxy.


9
È un po 'più corretto affermare che ogni chiamata di funzione ha un ambito. In altre parole, ciò che confonde thisin Javascript è che non è una proprietà intrinseca della funzione stessa, ma piuttosto un artefatto del modo in cui viene invocata la funzione.
Pointy,

@pointy grazie. ciò che causa più confusione in questo in js è il fatto che in tutti i linguaggi usati in precedenza (c #, c ++), questo non può essere manipolato n punta sempre all'istanza dell'oggetto mentre in js dipende e può essere cambiato quando si invoca funzioni usando func.call, func.bindecc. - Sushil
Sushil

2
thisnon senza riferimento portata di una funzione. thisfarà riferimento a un oggetto specifico (o possibilmente undefined), che come hai detto può essere modificato utilizzando .call()o .apply(). L' ambito di una funzione è (essenzialmente, quando semplificato) a quali variabili ha accesso, e questo dipende interamente da dove viene dichiarata la funzione e non può essere modificata.
nnnnnn,

@Pointy: "È un po 'più corretto dire che ogni chiamata di funzione ha un ambito." Ancora più corretto dire che le funzioni (e ora i blocchi) hanno un ambito , le chiamate alle funzioni hanno un contesto . L'ambito definisce quali sono gli identificatori che possono essere utilizzati dal codice in tale ambito. Il contesto definisce a cosa sono legati quegli identificatori.
TJ Crowder,

1
"Qualunque sia lo scopo, si fa riferimento a" questo "." No, thise l'ambito non ha nulla a che fare l'uno con l'altro in ES5 e prima (ad esempio, quando è stata scritta questa risposta). In ES2015 (alias ES6), l' thisambito è correlato in un modo abbastanza minimale alle funzioni freccia (la funzione thisin una freccia è ereditata dal suo ambito racchiuso), ma thisnon si riferisce mai a un ambito.
TJ Crowder,

10

Ecco una buona fonte di thisinJavaScript .

Ecco il riassunto:

  • globale questo

    In un browser, nell'ambito globale, thisè l' windowoggetto

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"

    Nell'uso di noderepl, thisè lo spazio dei nomi principale. Puoi fare riferimento ad esso come global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true

    In nodeesecuzione da uno script, thisin ambito globale inizia come un oggetto vuoto. Non è lo stesso diglobal

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
  • questa funzione

Tranne nel caso dei gestori di eventi DOM o quando thisArgviene fornito un (vedere più avanti), sia nel nodo che in un browser utilizzando thisuna funzione che non viene chiamata con newriferimenti all'ambito globale ...

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Se usi use strict;, nel qual caso thislo saràundefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

Se si chiama una funzione con newl' thissarà un nuovo contesto, non farà riferimento globale this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • prototipo questo

Le funzioni create diventano oggetti funzione. Ricevono automaticamente una prototypeproprietà speciale , che è qualcosa a cui puoi assegnare valori. Quando si crea un'istanza chiamando la propria funzione, newsi ottiene l'accesso ai valori assegnati alla prototypeproprietà. Puoi accedere a questi valori usando this.

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

Di solito è un errore assegnare matrici o oggetti su prototype. Se si desidera che le istanze abbiano le proprie matrici, crearle nella funzione, non nel prototipo.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • obiettare questo

È possibile utilizzare thisin qualsiasi funzione su un oggetto per fare riferimento ad altre proprietà su quell'oggetto. Non è la stessa di un'istanza creata con new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • DOM evento questo

In un gestore di eventi DOM HTML, thisè sempre un riferimento all'elemento DOM a cui è stato associato l'evento

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

A meno che tu non sia bindil contesto

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML questo

All'interno degli attributi HTML in cui è possibile inserire JavaScript, thisè un riferimento all'elemento.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • valutare questo

È possibile utilizzare evalper accedere this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • con questo

È possibile utilizzare withper aggiungere thisall'ambito corrente per leggere e scrivere su valori thissenza fare riferimento thisesplicitamente.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery questo

jQuery farà riferimento in molti punti thisa un elemento DOM.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

9

Daniel, spiegazione fantastica! Un paio di parole su questo e buona lista dithis puntatori di contesto esecuzione in caso di gestori di eventi.

In due parole, this in JavaScript punta l'oggetto da cui (o dal cui contesto di esecuzione) è stata eseguita la funzione corrente ed è sempre di sola lettura, non è possibile impostarla comunque (tale tentativo finirà con 'Mancata mano sinistra lato nel messaggio di assegnazione.

Per i gestori di eventi: i gestori di eventi inline, come ad esempio <element onclick="foo">, hanno la precedenza su tutti gli altri gestori collegati prima e prima, quindi fai attenzione ed è meglio evitare la delega degli eventi in linea. E grazie a Zara Alaverdyan che mi ha ispirato a questo elenco di esempi attraverso un dibattito dissenziente :)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

9

C'è molta confusione riguardo al modo in cui "questa" parola chiave viene interpretata in JavaScript. Spero che questo articolo riposi tutti quelli che riposano una volta per tutte. E molto di più. Si prega di leggere attentamente l'intero articolo. Tieni presente che questo articolo è lungo.

Indipendentemente dal contesto in cui viene utilizzato, "this" fa sempre riferimento all ' "oggetto corrente" in Javascript. Tuttavia, ciò che "l'oggetto corrente" è diverso a seconda del contesto . Il contesto può essere esattamente 1 dei 6 seguenti:

  1. Globale (ovvero al di fuori di tutte le funzioni)
  2. Chiamata interna "Funzione non vincolata" diretta (ovvero una funzione che non è stata associata chiamando il nome function.bind )
  3. Chiamata indiretta "Funzione non vincolata" tramite functionName.call e functionName.apply
  4. All'interno della chiamata "Funzione rilegata" (ovvero una funzione che è stata associata chiamando il nome function.bind )
  5. Mentre la creazione di oggetti tramite "nuovo"
  6. Gestore di eventi DOM Inline interno

Quanto segue descrive ciascuno di questi contesti uno per uno:

  1. Contesto globale (ovvero al di fuori di tutte le funzioni):

    Al di fuori di tutte le funzioni (cioè nel contesto globale) l ' "oggetto corrente" (e quindi il valore di "questo" ) è sempre l' oggetto "finestra" per i browser.

  2. Chiamata interna diretta "Funzione non vincolata" :

    All'interno di una chiamata diretta "Funzione non vincolata", l'oggetto che ha invocato la chiamata di funzione diventa "l'oggetto corrente" (e quindi il valore di "questo" ). Se una funzione viene chiamata senza un oggetto corrente esplicito , l' oggetto corrente è l' oggetto "finestra" (per la modalità non rigorosa) o non definito (per la modalità rigorosa). Qualsiasi funzione (o variabile) definita nel contesto globale diventa automaticamente una proprietà dell'oggetto "finestra". Ad esempio supponiamo che la funzione sia definita nel contesto globale come

    function UserDefinedFunction(){
        alert(this)
        }

    diventa la proprietà dell'oggetto finestra, come se fosse stato definito come

    window.UserDefinedFunction=function(){
      alert(this)
    }  

    In "Modalità non rigida", la chiamata / invocazione di questa funzione direttamente tramite "UserDefinedFunction ()" la chiamerà / invocherà automaticamente come "window.UserDefinedFunction ()" rendendo "window" come "oggetto corrente" (e quindi il valore di " this " ) in " UserDefinedFunction ". Se si attiva questa funzione in" Modalità non rigorosa ", si otterrà il seguente

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()

    In "Strict Mode", Calling / Richiamo della funzione direttamente tramite "UserDefinedFunction ()" si "NOT" richiamare automaticamente / lanciare come "window.UserDefinedFunction ()" .Hence il "oggetto corrente" (e il valore di "questa" ) all'interno di "UserDefinedFunction" non sarà definito . Il richiamo di questa funzione in "Modalità rigorosa" comporterà quanto segue

    UserDefinedFunction() // displays undefined

    Tuttavia, invocandolo in modo esplicito utilizzando l'oggetto finestra si ottiene quanto segue

    window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."

    Vediamo un altro esempio. Si prega di guardare il seguente codice

     function UserDefinedFunction()
        {
            alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
        }
    
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
          }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    o1.f() // Shall display 1,2,undefined,undefined
    o2.f() // Shall display undefined,undefined,3,4

    Nell'esempio precedente vediamo che quando "UserDefinedFunction" è stato invocato attraverso o1 , "this" assume il valore di o1 e viene visualizzato il valore delle sue proprietà "a" e "b" . Il valore di "c" e "d" sono stati indicati come indefiniti come o1 non definisce queste proprietà

    Allo stesso modo quando "UserDefinedFunction" è stato invocato tramite o2 , "this" assume il valore di o2 e viene visualizzato il valore delle sue proprietà "c" e "d" . Il valore di "a" e "b" sono visualizzati come indefiniti come fa o2 non definire queste proprietà.

  3. Chiamata indiretta "Funzione non vincolata" tramite functionName.call e functionName.apply :

    Quando viene chiamata una "Funzione non vincolata" tramite functionName.call o functionName.apply , l ' "oggetto corrente" (e quindi il valore di "questo" ) viene impostato sul valore di "questo" parametro (primo parametro) passato alla chiamata / applica . Il seguente codice dimostra lo stesso.

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
           }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
    UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
    
    UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
    UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
    
    o1.f.call(o2) // Shall display undefined,undefined,3,4
    o1.f.apply(o2) // Shall display undefined,undefined,3,4
    
    o2.f.call(o1) // Shall display 1,2,undefined,undefined
    o2.f.apply(o1) // Shall display 1,2,undefined,undefined

    Il codice sopra mostra chiaramente che il valore "this" per qualsiasi "Funzione NON vincolata" può essere modificato tramite call / apply . Inoltre, se il parametro "questo" non viene passato esplicitamente a call / apply , "oggetto corrente" (e quindi il valore di "questo") viene impostato su "finestra" in modalità Non rigorosa e "non definito" in modalità rigorosa.

  4. All'interno della chiamata "Bound Function" (ovvero una funzione che è stata associata chiamando il nome function.bind ):

    Una funzione associata è una funzione il cui "questo" valore è stato corretto. Il codice seguente ha dimostrato come funziona "this" in caso di funzione associata

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
              a:1,
              b:2,
              f:UserDefinedFunction,
              bf:null
           }
    var o2={
               c:3,
               d:4,
               f:UserDefinedFunction,
               bf:null
            }
    
    var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
    bound1() // Shall display 1,2,undefined,undefined
    
    var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
    bound2() // Shall display undefined,undefined,3,4
    
    var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
    bound3() // Shall display undefined,undefined,3,4
    
    var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
    bound4() // Shall display 1,2,undefined,undefined
    
    o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
    o1.bf() // Shall display undefined,undefined,3,4
    
    o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
    o2.bf() // Shall display 1,2,undefined,undefined
    
    bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    
    bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
    
    o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function

    Come indicato nel codice sopra, "questo" valore per qualsiasi "Funzione legata" NON PUO 'essere modificato tramite call / apply . Inoltre, se il parametro "this" non viene passato esplicitamente a bind, "object corrente" (e quindi il valore di "this" ) viene impostato su "window" in modalità Non rigorosa e "non definito" in modalità rigorosa. Un'altra cosa. Associare una funzione già associata non cambia il valore di "this" . Resta impostato come valore impostato dalla funzione di primo bind.

  5. Mentre la creazione di oggetti tramite "nuovo" :

    All'interno di una funzione di costruzione, "l'oggetto corrente" (e quindi il valore di "questo" ) fa riferimento all'oggetto che viene attualmente creato tramite "nuovo", indipendentemente dallo stato di associazione della funzione. Tuttavia, se il costruttore è una funzione associata, verrà chiamato con un set predefinito di argomenti come impostato per la funzione associata.

  6. Gestore di eventi DOM Inline interno :

    Si prega di guardare il seguente frammento HTML

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>

    Il "questo" negli esempi precedenti si riferisce rispettivamente all'elemento "button" e all'elemento "div".

    Nel primo esempio, il colore del carattere del pulsante deve essere impostato su bianco quando viene cliccato.

    Nel secondo esempio quando si fa clic sull'elemento "div" , si chiamerà la funzione OnDivClick con il suo secondo parametro che fa riferimento all'elemento div cliccato. Tuttavia, il valore di "this" in OnDivClick NON farà riferimento all'elemento div cliccato . Deve essere impostato come "oggetto finestra" o "non definito" rispettivamente nelle modalità Non rigoroso e Rigido (se OnDivClick è una funzione non associata ) o impostato su un valore Bound predefinito (se OnDivClick è una funzione associata )

Quanto segue riassume l'intero articolo

  1. Nel contesto globale "questo" si riferisce sempre all'oggetto "finestra"

  2. Ogni volta che una funzione viene invocata, viene invocata nel contesto di un oggetto ( "oggetto corrente" ). Se l' oggetto corrente non viene fornito in modo esplicito, l' oggetto corrente è "oggetto finestra" in modalità NON rigorosa e "non definito" in modalità rigorosa per impostazione predefinita.

  3. Il valore di "this" all'interno di una funzione non vincolata è il riferimento all'oggetto nel contesto del quale viene invocata la funzione ( "oggetto corrente" )

  4. Il valore di "this" all'interno di una funzione non vincolata può essere sostituito da una chiamata e applicare i metodi della funzione.

  5. Il valore di "this" è fisso per una funzione Bound e non può essere sostituito da chiamata e applicare i metodi della funzione.

  6. La funzione di associazione e già associata non modifica il valore di "this". Resta impostato come valore impostato dalla funzione di primo bind.

  7. Il valore di "this" in un costruttore è l'oggetto che viene creato e inizializzato

  8. Il valore di "this" all'interno di un gestore di eventi DOM inline fa riferimento all'elemento per il quale viene fornito il gestore di eventi.


9

Probabilmente l'articolo più dettagliato e completo su this è il seguente:

Spiegazione delicata di questa "parola chiave" in JavaScript

L'idea alla base thisè capire che i tipi di invocazione delle funzioni hanno un'importanza significativa sull'impostazione del thisvalore.


Quando si riscontrano problemi di identificazione this, non chiedersi:

Da dove viene thispreso ?

ma non chiedetevi:

Come viene invocata la funzione ?

Per una funzione freccia (caso speciale di trasparenza del contesto) chiediti:

Quale valore ha thisdove è definita la funzione freccia ?

Questa mentalità è corretta quando si tratta di thise ti salverà dal mal di testa.


Oltre al collegamento al tuo blog, forse potresti approfondire un po 'come porre queste domande aiuta qualcuno a capire la thisparola chiave?
Magnus Lind Oxlund,

7

Questa è la migliore spiegazione che ho visto: capire JavaScripts questo con Clarity

Il questo riferimento si riferisce sempre (e mantiene il valore di) un oggetto, un singolare oggetto, e di solito è utilizzato all'interno di una funzione o un metodo, anche se può essere usato fuori da una funzione nell'ambito globale. Si noti che quando si utilizza la modalità rigorosa, questo detiene il valore di indefinito nelle funzioni globali e nelle funzioni anonime che non sono associate a nessun oggetto.

Esistono quattro scenari in cui ciò può creare confusione:

  1. Quando si passa un metodo (che utilizza questo ) come argomento per essere usato come una funzione di richiamata.
  2. Quando usiamo una funzione interna (una chiusura). È importante notare che le chiusure non possono accedere a questa variabile della funzione esterna utilizzando questa parola chiave perché questa variabile è accessibile solo dalla funzione stessa, non dalle funzioni interne.
  3. Quando un metodo che si basa su questo viene assegnato a una variabile tra contesti, nel qual caso questo fa riferimento a un altro oggetto di quanto inizialmente previsto.
  4. Quando si utilizza questo insieme ai metodi bind, apply e call.

Fornisce esempi di codice, spiegazioni e soluzioni, che ho ritenuto molto utili.


6

In termini pseudoclassici, il modo in cui molte lezioni insegnano la parola chiave "this" è come un oggetto creato da una classe o da un costruttore di oggetti. Ogni volta che un nuovo oggetto viene costruito da una classe, immagina che sotto il cofano venga creata e restituita un'istanza locale di un oggetto "questo". Ricordo che ha insegnato così:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;

5

thisè uno dei concetti incompresi in JavaScript perché si comporta in modo leggermente diverso da un luogo all'altro. Semplicemente, si thisriferisce al "proprietario" della funzione che stiamo attualmente eseguendo .

thisaiuta a ottenere l'oggetto corrente (aka contesto di esecuzione) con cui lavoriamo. Se capisci in quale oggetto viene eseguita la funzione corrente, puoi capire facilmente quale thissia la corrente

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Sopra creiamo 3 variabili con lo stesso nome 'val'. Uno nel contesto globale, uno all'interno di obj e l'altro all'interno del metodo interno di obj. JavaScript risolve gli identificatori in un particolare contesto salendo la catena dell'ambito da locale a globale.


Pochi posti dove si thispuò differenziare

Chiamare un metodo di un oggetto

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Quando viene eseguita la riga 1, JavaScript stabilisce un contesto di esecuzione (EC) per la chiamata di funzione, impostando thisl' oggetto a cui fa riferimento qualunque cosa sia venuta prima dell'ultimo "." . quindi nell'ultima riga puoi capire che è a()stato eseguito nel contesto globale che è il window.

Con costruttore

this può essere utilizzato per fare riferimento all'oggetto che viene creato

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Quando Person()viene eseguito new, viene creato un oggetto completamente nuovo. Personviene chiamato ed thisè impostato per fare riferimento a quel nuovo oggetto.

Chiamata di funzione

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

Se ci manca la newparola chiave, fa riferimento whatIsThisal contesto più globale che può trovare ( window)

Con gestori di eventi

Se il gestore eventi è in linea, si thisriferisce all'oggetto globale

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

Quando si aggiunge il gestore eventi tramite JavaScript, si thisriferisce all'elemento DOM che ha generato l'evento.



5

Il valore di "this" dipende dal "contesto" in cui viene eseguita la funzione. Il contesto può essere qualsiasi oggetto o oggetto globale, ovvero finestra.

Quindi la semantica di "questo" è diversa dalle tradizionali lingue OOP. E causa problemi: 1. quando una funzione viene passata a un'altra variabile (molto probabilmente, una richiamata); e 2. quando viene invocata una chiusura da un metodo membro di una classe.

In entrambi i casi, questo è impostato su window.


3

Questo dovrebbe aiutare? (La maggior parte della confusione di "questo" in javascript deriva dal fatto che generalmente non è collegato al tuo oggetto, ma all'attuale ambito di esecuzione - potrebbe non essere esattamente come funziona ma mi sembra sempre così - vedi l'articolo per una spiegazione completa)


1
Sarebbe meglio dire che è collegato " al contesto di esecuzione corrente ". Tranne ES6 (bozza) cambia quello con le funzioni freccia, dove questo viene risolto nel contesto di esecuzione esterno.
RobG

3

Un po 'di informazioni su questo parola chiave

Registriamo la thisparola chiave sulla console nell'ambito globale senza altro codice

console.log(this)

Nel client / browser la this parola chiave è un oggetto globale che èwindow

console.log(this === window) // true

e

Nel Server / Nodo / Javascript la this parola chiave runtime è anche un oggetto globalemodule.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

Tieni presente che exportsè solo un riferimento amodule.exports


1

questo uso per Scope è proprio così

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

il valore di txt1 e txt è lo stesso nell'esempio precedente $ (this) = $ ('# tbleName tbody tr') è uguale


1

Ho un approccio diverso this dalle altre risposte che spero siano utili.

Un modo per guardare JavaScript è vedere che esiste solo 1 modo per chiamare una funzione 1 . È

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

C'è sempre un valore fornito per objectForThis.

Tutto il resto è zucchero sintattico per functionObject.call

Quindi, tutto il resto può essere descritto da come si traduce functionObject.call.

Se chiami semplicemente una funzione, allora thisè "l'oggetto globale" che nel browser è la finestra

function foo() {
  console.log(this);
}

foo();  // this is the window object

In altre parole,

foo();

è stato effettivamente tradotto in

foo.call(window);

Si noti che se si utilizza la modalità rigorosa, thislo saràundefined

'use strict';

function foo() {
  console.log(this);
}

foo();  // this is the window object

che significa

In altre parole,

foo();

è stato effettivamente tradotto in

foo.call(undefined);

In JavaScript ci sono operatori come +e -e *. C'è anche l'operatore punto che è.

L' .operatore quando utilizzato con una funzione a destra e un oggetto a sinistra significa effettivamente "passa oggetto comethis riguarda la funzione.

Esempio

const bar = {
  name: 'bar',
  foo() { 
    console.log(this); 
  },
};

bar.foo();  // this is bar

In altre parole si bar.foo()traduce inconst temp = bar.foo; temp.call(bar);

Nota che non importa come è stata creata la funzione (principalmente ...). Tutti questi produrranno gli stessi risultati

const bar = {
  name: 'bar',
  fn1() { console.log(this); },
  fn2: function() { console.log(this); },
  fn3: otherFunction,
};

function otherFunction() { console.log(this) };

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

Ancora una volta, tutti questi sono solo zucchero sintattico per

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

Un'altra ruga è la catena del prototipo. Quando si utilizza a.bJavaScript, prima cerca l'oggetto a cui fa riferimento direttamente ala proprietà b. Se bnon viene trovato sull'oggetto, JavaScript cercherà nel prototipo dell'oggetto da trovare b.

Esistono vari modi per definire il prototipo di un oggetto, il più comune nel 2019 è la classparola chiave. Ai fini di thissebbene non importa. Ciò che conta è che poiché cerca nell'oggetto auna proprietà bse trova una proprietà bsull'oggetto o nella sua catena di prototipi se bfinisce per essere una funzione, valgono le stesse regole di cui sopra. I briferimenti di funzione verranno chiamati utilizzando il callmetodo e il passaggioa come objectForThis come mostrato all'inizio di questa risposta.

Adesso. Immaginiamo di creare una funzione che imposta esplicitamente thisprima di chiamare un'altra funzione e quindi chiamarla con l' .operatore (punto)

function foo() {
  console.log(this);
}

function bar() {
  const objectForThis = {name: 'moo'}
  foo.call(objectForThis);  // explicitly passing objectForThis
}

const obj = {
  bar,
};

obj.bar();  

A seguito della traduzione da utilizzare call, obj.bar()diventa const temp = obj.bar; temp.call(obj);. Quando entriamo nella barfunzione che chiamiamo, fooma passiamo esplicitamente in un altro oggetto per objectForThis così quando arriviamo a foo thisè quell'oggetto interno.

Questo è ciò che sia binde =>funzioni in maniera efficace fanno. Sono più zuccheri sintattici. Costruiscono efficacemente una nuova funzione invisibile esattamente come barsopra che imposta esplicitamente thisprima di chiamare qualunque funzione sia specificata. Nel caso di bind thisè impostato su qualunque cosa passi bind.

function foo() {
  console.log(this);
}

const bar = foo.bind({name: 'moo'});

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call({name: 'other'});

Nota che se functionObject.bindnon esistesse potremmo crearne uno nostro come questo

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

e quindi potremmo chiamarlo così

function foo() {
  console.log(this);
}

const bar = bind(foo, {name:'abc'});

Le funzioni della freccia, l' =>operatore sono zucchero sintattico per il legame

const a = () => {console.log(this)};

equivale a

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

Proprio come bind, viene creata una nuova funzione invisibile che chiama la funzione data con un valore associato objectForThisma, diversamente binddall'oggetto da associare, è implicita. È qualunque cosa thisaccada quando il=> si utilizza operatore.

Quindi, proprio come le regole sopra

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo()si traduce in const temp = obj.foo; temp.call(obj);ciò significa che l'operatore freccia all'interno foosi legherà obja una nuova funzione invisibile e restituirà quella nuova funzione invisibile a cui è assegnato b. b()funzionerà come sempre b.call(window)o come b.call(undefined)chiamando la nuova funzione invisibile che ha foocreato. Quella funzione invisibile ignora il thispassato e passaobj come oggetto Per questo alla funzione freccia.

Il codice sopra si traduce in

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply è un'altra funzione simile acall

functionName.apply(objectForThis, arrayOfArgs);

Ma a partire da ES6 concettualmente puoi persino tradurlo in

functionName.call(objectForThis, ...arrayOfArgs);

0

Riepilogo thisJavascript:

  • Il valore di thisè determinato da come la funzione non viene invocata, da dove è stata creata!
  • Di solito il valore di thisè determinato dall'Oggetto che è rimasto del punto. (window nello spazio globale)
  • In caso di ascoltatori il valore di this riferisce all'elemento DOM su cui è stato chiamato l'evento.
  • Quando in funzione viene chiamato con la newparola chiave il valore dithis riferisce all'oggetto appena creato
  • È possibile modificare il valore di thiscon le funzioni: call, apply,bind

Esempio:

let object = {
  prop1: function () {console.log(this);}
}

object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

Esempio di listener di eventi:

document.querySelector('.foo').addEventListener('click', function () {
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
})


document.querySelector('.foo').addEventListener('click', () => {
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
})                    // Therefore this will log the global object
.foo:hover {
  color: red;
  cursor: pointer;
}
<div class="foo">click me</div>

Costruttore di esempio:

function Person (name) {
  this.name = name;
}

const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.


0

Per comprendere "questo" in modo corretto è necessario comprendere il contesto, l'ambito e la differenza tra di essi.

Scope : in javascript l'ambito è legato alla visibilità delle variabili, l'ambito raggiunge attraverso l'uso della funzione. (Maggiori informazioni sull'ambito)

Contesto : il contesto è correlato agli oggetti. Si riferisce all'oggetto a cui appartiene una funzione. Quando si utilizza la parola chiave JavaScript "questo", si riferisce all'oggetto a cui appartiene la funzione. Ad esempio, all'interno di una funzione, quando dici: “this.accoutNumber”, ti riferisci alla proprietà “accoutNumber”, che appartiene all'oggetto a cui appartiene quella funzione.

Se l'oggetto "myObj" ha un metodo chiamato "getMyName", quando la parola chiave JavaScript "this" viene utilizzata all'interno di "getMyName", si riferisce a "myObj". Se la funzione "getMyName" è stata eseguita nell'ambito globale, allora "this" si riferisce all'oggetto window (tranne che in modalità rigorosa).

Ora vediamo qualche esempio:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

Eseguendo il codice sull'output del browser sarà: inserisci qui la descrizione dell'immagine

Secondo l'output che si trova all'interno del contesto dell'oggetto finestra, è anche visibile che il prototipo di finestra si riferisce all'oggetto.

Ora proviamo all'interno di una funzione:

    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>

Produzione:

inserisci qui la descrizione dell'immagine L'output è lo stesso perché abbiamo registrato 'questa' variabile nell'ambito globale e l'abbiamo registrato nell'ambito funzionale, non abbiamo cambiato il contesto. In entrambi i casi il contesto era lo stesso, correlato all'oggetto vedova .

Ora creiamo il nostro oggetto. In JavaScript, puoi creare un oggetto in molti modi.

 <script>
        var firstName = "Nora";
        var lastName = "Zaman";
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printNameGetContext:function(){
                console.log(firstName + " "+lastName);
                console.log(this.firstName +" "+this.lastName);
                return this;
            }
        }

      var context = myObj.printNameGetContext();
      console.log(context);
    </script>

Produzione: inserisci qui la descrizione dell'immagine

Quindi, dall'esempio precedente, abbiamo scoperto che "questa" parola chiave si riferisce a un nuovo contesto correlato a myObj e myObject ha anche una catena di prototipi su Object.

Facciamo un altro esempio:

<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>

uscita: ha senso vero? (leggi commenti) inserisci qui la descrizione dell'immagine

Se hai problemi a comprendere l'esempio sopra, proviamo con il nostro callback;

<script>
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printName:function(callback1, callback2){
                //Attaching callback1 with this myObj context
                this.callback1 = callback1;
                this.callback1(this.firstName +" "+this.lastName)
                //We did not attached callback2 with myObj so, it's reamin with window context by default
                callback2();
                /*
                 //test bellow codes
                 this.callback2 = callback2;
                 this.callback2();
                */
            }
        }
        var callback2 = function (){
            console.log(this);
        }
        myObj.printName(function(data){
            console.log(data);
            console.log(this);
        }, callback2);
    </script>

produzione: inserisci qui la descrizione dell'immagine

Ora comprendiamo Scope, Self, IIFE e QUESTO come si comporta

       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script> 

L'output è davvero fantastico, vero? inserisci qui la descrizione dell'immagine


-1

Risposta semplice:

La parola chiave "this" dipende sempre dal contesto dell'invocazione. Sono menzionati di seguito.

  1. LA FUNZIONE È CHIAMATA CON LA NUOVA PAROLA CHIAVE

    Se la funzione viene chiamata con NUOVA parola chiave, QUESTO verrà associato all'oggetto appena creato.

    function Car(){
      this.name="BMW";
    }
    const myCar=new Car();
    myCar.name; // output "BMW"

    Quanto sopra sarà associato all'oggetto "myCar"

  2. LA FUNZIONE È CHIAMATA ESPLICITAMENTE MEDIANTE CHIAMATA E APPLICAZIONE DI METODI.

    In questo caso, QUESTO verrà associato all'oggetto che viene esplicitamente passato alla funzione.

    var obj1={"name":"bond"};
    function printMessage(msg){
        return msg+" "+this.name;
    }
    const message=printMessage.call(obj1,"my name is ");
    console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO.
  3. SE LA FUNZIONE È CHIAMATA CON L'OGGETTO IMPLICITAMENTE POI QUESTO SARA 'COLLEGATO A QUESTO OGGETTO

    var obj1={
       "name":"bond",
        getName: function () {
                    return this.name;
                 }
    };
    const newname=obj1.getName();
    console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT)
  4. QUANDO LA FUNZIONE È CHIAMATA SENZA ALCUN CONTESTO, QUESTA SARÀ LEGATA ALL'OGGETTO GLOBALE

    const util = {
       name: 'Utility',
       getName: function () {
                    return this.name;
    };
    
    const getName=util.getName;
    const newName=getName();
    console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE  BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT
  5. IN MODO RIGIDO, QUESTO NON SARÀ DEFINITO

    function setName(name){
        "use strict"
        return this.name;
    }
    setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.