Cosa sta alla base di questo linguaggio JavaScript: var self = this?


357

Ho visto quanto segue nel sorgente per la demo delle note di archiviazione SQL 5 di WebKit HTML 5 :

function Note() {
  var self = this;

  var note = document.createElement('div');
  note.className = 'note';
  note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
  note.addEventListener('click', function() { return self.onNoteClick() }, false);
  this.note = note;
  // ...
}

L'autore usa il in alcuni punti (il corpo della funzione) e questo in altri luoghi (i corpi delle funzioni definiti nella lista degli argomenti dei metodi). Cosa sta succedendo? Ora che l'ho notato una volta, inizierò a vederlo ovunque?


4
Questa è una funzionalità del linguaggio JS chiamata "chiusura lessicale".
subZero

2
Possibile duplicato di: var self = this? .
DavidRR,

il concetto di QUESTO è spiegato esplicitamente qui scotch.io/@alZami/understanding-this-in-javascript
AL-zami

Esempio pertinente in questa risposta stackoverflow.com/a/20279485/5610569 (alla domanda "Come accedere al corretto thisall'interno di un callback?")
FluxLemur

Risposte:


431

Vedi questo articolo su alistapart.com . (Ed: l'articolo è stato aggiornato poiché originariamente collegato)

selfviene utilizzato per mantenere un riferimento all'originale thisanche se il contesto sta cambiando. È una tecnica spesso usata nei gestori di eventi (specialmente nelle chiusure).

Modifica: si noti che l'utilizzo selfè ora sconsigliato come window.selfesiste e ha il potenziale di causare errori se non si presta attenzione.

Ciò che chiami la variabile non ha particolare importanza. var that = this;va bene, ma non c'è nulla di magico nel nome.

Le funzioni dichiarate in un contesto (es. Callback, chiusure) avranno accesso alle variabili / funzioni dichiarate nello stesso ambito o sopra.

Ad esempio, un semplice callback di eventi:

function MyConstructor(options) {
  let that = this;

  this.someprop = options.someprop || 'defaultprop';

  document.addEventListener('click', (event) => {
    alert(that.someprop);
  });
}

new MyConstructor({
  someprop: "Hello World"
});


Sembra che l'articolo si sia trasformato in usovar that = this;
Bob Stein il

@BobStein Grazie. Aggiornerò la risposta di conseguenza.
Jonathan Fingland,

96

Penso che il nome della variabile 'self' non debba più essere utilizzato in questo modo, poiché i browser moderni forniscono una variabile globale cheself punta all'oggetto globale di una finestra normale o di un WebWorker.

Per evitare confusione e potenziali conflitti, puoi scrivere var thiz = thiso var that = thisinvece.


43
Di solito uso_this
djheru il

6
@djheru +1. molto più bello di " that" (a cui il mio cervello non si abituerà mai).
o_o_o--

9
Ho iniziato a usare "me" :)
Mopparthy Ravindranath il

3
Fino a quando i browser moderni non inizieranno a fornire una variabile globale _questo, questo o me.
Beejor,

10
Non c'è assolutamente alcun problema nell'usare il nome selffintanto che lo dichiari varaffidabile, oscurerà il globale. Naturalmente se lo dimenticassi var, non funzionerebbe con nessun altro nome.
Bergi,

34

Sì, lo vedrai ovunque. È spesso that = this;.

Vedi come selfviene utilizzato nelle funzioni chiamate dagli eventi? Quelli avrebbero il loro contesto, quindi selfè usato per contenere thisciò che è entrato Note().

Il motivo selfè ancora disponibile per le funzioni, anche se possono essere eseguite solo dopo che la Note()funzione ha terminato l'esecuzione, è che le funzioni interne ottengono il contesto della funzione esterna a causa della chiusura .


12
Per me il punto cogent è che selfnon ha alcun significato speciale. Personalmente preferisco usare una variante con un nome diverso da quello selfche mi confonde spesso, poiché mi aspetto che "sé" sia una parola riservata. Quindi mi piace la tua risposta. E nell'esempio del PO, preferirei var thisNote = thiso simili.
steve

@steve ha concordato, anche se cerco di evitare di utilizzare questo / riferimenti personali in generale in quanto sono molto fragili in termini di manutenibilità.
mattLummus

28

Va anche notato che esiste un modello proxy alternativo per mantenere un riferimento all'originale thisin un callback se non ti piace il var self = thislinguaggio.

Poiché una funzione può essere chiamata con un determinato contesto usando function.applyo function.call, è possibile scrivere un wrapper che restituisce una funzione che chiama la funzione con applyo callutilizzando il contesto dato. Vedi la proxyfunzione di jQuery per un'implementazione di questo modello. Ecco un esempio di come usarlo:

var wrappedFunc = $.proxy(this.myFunc, this);

wrappedFuncpuò quindi essere chiamato e avrà la tua versione di thiscome contesto.


10

Come altri hanno spiegato, var self = this;consente al codice in una chiusura di fare riferimento all'ambito padre.

Tuttavia, è ora il 2018 ed ES6 è ampiamente supportato da tutti i principali browser Web. Ilvar self = this; linguaggio non è così essenziale come una volta.

Ora è possibile evitare var self = this;attraverso l'uso delle funzioni freccia .

Nei casi in cui avremmo usato var self = this:

function test() {
    var self = this;
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", function() {
        console.log(self.hello); // logs "world"
    });
};

Ora possiamo usare una funzione freccia senza var self = this:

function test() {
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", () => {
        console.log(this.hello); // logs "world"
    });
};

Le funzioni freccia non hanno le proprie thise assumono semplicemente l'ambito di applicazione.


Oppure - shock, orrore! - perché non passare l'argomento attuale rilevante come argomento alla tua funzione (chiusura)? Perché diavolo ti riferisci al di fuori dello scopo, perché diavolo qualcuno sta programmando in questo modo? Non c'è mai alcun motivo reale per farlo. Anziché.addEventListender("click", (x) => { console.log(x); }); hai spiegato molto chiaramente come e perché, e concordo sull'uso delle funzioni freccia ha più senso, ma comunque ... questa è solo una programmazione terribile, pigra, disordinata.
Benjamin R,

2
In JavaScript, il riferimento all'ambito padre è estremamente comune e necessario. È una parte fondamentale della lingua. Il tuo suggerimento di passare nell'ambito genitore come argomento sul gestore eventi non è effettivamente possibile. Inoltre, in ES6, le funzioni freccia usano l'ambito lessicale - 'questo' si riferisce al suo ambito circostante attuale e non oltre - non è "riferimento fuori dallo stato dell'ambito" o qualcosa del genere.
Elliot B.

9

La variabile viene acquisita dalle funzioni incorporate definite nel metodo. thisnella funzione farà riferimento a un altro oggetto. In questo modo, è possibile fare in modo che la funzione mantenga un riferimento thisall'ambito esterno.


9

È una stranezza JavaScript. Quando una funzione è una proprietà di un oggetto, più appropriatamente chiamato metodo, questo si riferisce all'oggetto. Nell'esempio di un gestore eventi, l'oggetto contenitore è l'elemento che ha attivato l'evento. Quando viene invocata una funzione standard, questo farà riferimento all'oggetto globale. Quando hai funzioni nidificate come nel tuo esempio, questo non è affatto correlato al contesto della funzione esterna. Le funzioni interne condividono l'ambito con la funzione contenitiva, quindi gli sviluppatori useranno le variazioni var that = thisper preservare ciò di cui hanno bisogno nella funzione interna.


5

In realtà self è un riferimento a window (window.self ) quindi quando dici var self = 'something'di sovrascrivere un riferimento a se stesso - perché self esiste nell'oggetto window.

Questo è il motivo per cui la maggior parte degli sviluppatori preferisce var that = this overvar self = this;

Comunque; var that = this;non è in linea con le buone pratiche ... supponendo che il tuo codice verrà rivisto / modificato in seguito da altri sviluppatori, dovresti utilizzare gli standard di programmazione più comuni nel rispetto della comunità degli sviluppatori

Quindi dovresti usare qualcosa come var oldThis/ var oThis/ etc - per essere chiari nel tuo ambito // ..non è molto ma risparmierà pochi secondi e pochi cicli cerebrali


2
@prior Penso che abbia senso fino all'ultimo paragrafo.
miphe,

0

Come accennato più volte in precedenza, 'sé' viene semplicemente usato per mantenere un riferimento a 'questo' prima di entrare nella funzione. Una volta nella funzione 'questo' si riferisce a qualcos'altro.


@JohnPaul ... questo non fornire una risposta. Potrebbe non essere la risposta giusta, ma come si può dire che "viene utilizzato per ..." non è una risposta a "perché ha fatto questo"?
GreenAsJade,

-1
function Person(firstname, lastname) {
  this.firstname = firstname;

  this.lastname = lastname;
  this.getfullname = function () {
    return `${this.firstname}   ${this.lastname}`;
  };

  let that = this;
  this.sayHi = function() {
    console.log(`i am this , ${this.firstname}`);
    console.log(`i am that , ${that.firstname}`);
  };
}

let thisss = new Person('thatbetty', 'thatzhao');

let thatt = {firstname: 'thisbetty', lastname: 'thiszhao'};

thisss.sayHi.call (thatt);


1
Dovresti aggiungere alcune spiegazioni con il codice che cosa hai fatto di speciale.
Farhana,
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.