Cosa significa "var that = this;" intendi in JavaScript?


351

In un file JavaScript ho visto:

function Somefunction(){
   var that = this; 
   ... 
}

Qual è lo scopo di dichiararlo thate assegnarglielo this?


3
possibile duplicato di var self = this?
Bergi,

6
"Questo" e "quello" hack non sono richiesti per le funzioni freccia. Con le funzioni freccia "questo" funziona come previsto. Vedi qui per maggiori dettagli ES6
satguru srivastava

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

Una grande spiegazione su questo comportamento misterioso basata sul contesto qui
RBT

La spiegazione più recente e aggiornata è disponibile qui
Sukrit Gupta,

Risposte:


486

Inizierò questa risposta con un'illustrazione:

var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
    // this is a reference to the element clicked on

    var that = this;

    colours.forEach(function() {
        // this is undefined
        // that is a reference to the element clicked on
    });
});

La mia risposta inizialmente lo ha dimostrato con jQuery, che è solo leggermente diverso:

$('#element').click(function(){
    // this is a reference to the element clicked on

    var that = this;

    $('.elements').each(function(){
        // this is a reference to the current element in the loop
        // that is still a reference to the element clicked on
    });
});

Poiché thiscambia frequentemente quando si modifica l'ambito chiamando una nuova funzione, non è possibile accedere al valore originale utilizzandolo. Alias ​​per thatconsentire ancora di accedere al valore originale di this.

Personalmente, non mi piace l'uso thatcome alias. Raramente è ovvio a cosa si riferisca, specialmente se le funzioni sono più lunghe di un paio di righe. Ho sempre utilizzare un alias più descrittivo. Nei miei esempi sopra, probabilmente userei clickedEl.


149
Di solito vado con var self = this;. La parola thatsembra implicare che la variabile è qualcosa MA this.
David Murdoch,

13
@ David Sì, ho pensato che fosse in qualche modo fuorviante. Ma se, come dice Crockford, è una convenzione, è saggio percorrere quella strada. Sono totalmente d'accordo con te, però ha molto più senso.
El Ronnoco,

4
@El Ronnoco, ma "Ha i capelli grigi e una barba sciatta e i suoi modi fanno venire in mente un vecchio scontroso che grida ai bambini di scendere dal suo prato." - blogging.compendiumblog.com/blog/software-for-humans/0/0/… ;-p
David Murdoch,

7
@ElRonnoco: Questo è un appello all'autorità, però. Se facciamo solo ciò che "i personaggi famosi" dicono che dovremmo fare, siamo diretti al disastro.
Lightness Races in Orbit

3
La forEachfunzione accetta un secondo argomento facoltativo che è l'associazione della funzione. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);Quindi dovrebbe essere aggiunta una nota che in realtàvar that = this non è necessaria . forEach
Matt Clarkson,

107

Da Crockford

Per convenzione, rendiamo privata quella variabile. Questo è usato per rendere l'oggetto disponibile ai metodi privati. Questa è una soluzione alternativa per un errore nelle specifiche del linguaggio ECMAScript che causa l' impostazione errata delle funzioni interne.

JS Fiddle

function usesThis(name) {
    this.myName = name;

    function returnMe() {
        return this;        //scope is lost because of the inner function
    }

    return {
        returnMe : returnMe
    }
}

function usesThat(name) {
    var that = this;
    this.myName = name;

    function returnMe() {
        return that;            //scope is baked in with 'that' to the "class"
    }

    return {
        returnMe : returnMe
    }
}

var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
      "UsesThis thinks it's called " + usesthis.returnMe().myName);

Questo avvisa ...

Questo pensa che si chiami Dave

Usi Questo pensa che sia chiamato indefinito


2
Grazie, riassume abbastanza bene per me.
Chris,

3
L'ho letto, non ho capito perché non aveva dettagli, cercato su Google, trovato questa pagina. Dove sono di nuovo indicato la stessa frase. Da qui il downvote.
Aditya MP,

3
Questo è un punto giusto, direi che qualcuno che non ha familiarità con JavaScript avrebbe difficoltà a cogliere il concetto dalla mia sola risposta. Ho risposto molto brevemente (e ho fatto un collegamento alla pagina per cui hai cercato su Google ..) Direi che la risposta di solitario è la più chiara, anche se l'avrei comunque preferita in JS piuttosto che in un esempio di jQuery.
El Ronnoco,

16
Non mi offendo. È bello vedere qualcuno che commenta durante il downvoting!
El Ronnoco,

4
Il problema con la risposta di Crockford è che la thatvariabile non è affatto utilizzata nel suo esempio. Sembra che la sola creazione di una tenuta variabile thisfaccia qualcosa per il resto del codice.
r3m0t,

86

Questo è un trucco per far funzionare le funzioni interne (funzioni definite all'interno di altre funzioni) più come dovrebbero. In javascript quando si definisce una funzione all'interno di un'altra thisviene automaticamente impostata sull'ambito globale. Questo può essere fonte di confusione perché ci si aspetta thische abbia lo stesso valore della funzione esterna.

var car = {};
car.starter = {};

car.start = function(){
    var that = this;

    // you can access car.starter inside this method with 'this'
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to the global scope
        // 'this.starter' is undefined, so we use 'that' instead.
        that.starter.active = true;

        // you could also use car.starter, but using 'that' gives
        // us more consistency and flexibility
    };

    activateStarter();

};

Questo è specificamente un problema quando si crea una funzione come metodo di un oggetto (come car.startnell'esempio), quindi si crea una funzione all'interno di quel metodo (come activateStarter). Nel metodo di livello superiore thispunta all'oggetto è un metodo di (in questo caso car) , ma nella funzione interna thisora punta all'ambito globale. Questo è un dolore

La creazione di una variabile da usare per convenzione in entrambi gli ambiti è una soluzione per questo problema molto generale con javascript (anche se è utile anche nelle funzioni jquery). Questo è il motivo per cui thatviene usato il nome dal suono molto generale . È una convenzione facilmente riconoscibile per superare un difetto nella lingua.

Come suggerisce El Ronnoco a Douglas Crockford, questa è una buona idea.


8
Suppongo che questa sia una risposta più utile di una accettata. Perché chiarisce il motivo per cui Crockford ha inventato "quello" mentre la risposta su jQuery non lo fa.
Konstantin Smolyanin,

4
Questo è in realtà un esempio migliore della risposta accettata. Spiega cosa significa "un errore nelle specifiche del linguaggio ECMAScript che causa una errata impostazione delle funzioni interne", afferma Douglas.
Kakacii,

1
Tuttavia potresti voler renderlo grammaticale corretto. So che è più simile a un errore di battitura, ma potrebbe confondere i principianti javascript in quanto questa domanda è più simile a un principiante. Voglio dire che dovrebbe essere: var car = {}; car.starter = {}; car.start = function () {...}
kakacii

1
@kakacii Grazie. Riparato ora.
Waylon Flinn,

9

L'uso di thatnon è veramente necessario se si esegue una soluzione alternativa con l'uso di call()o apply():

var car = {};
car.starter = {};

car.start = function(){
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to our main object
        this.starter.active = true;
    };

    activateStarter.apply(this);
};

3

A volte thispuò fare riferimento a un altro ambito e fare riferimento a qualcos'altro, ad esempio supponiamo di voler chiamare un metodo di costruzione all'interno di un evento DOM, in questo caso thisfarà riferimento all'elemento DOM e non all'oggetto creato.

HTML

<button id="button">Alert Name</button>

JS

var Person = function(name) {
  this.name = name;
  var that = this;
  this.sayHi = function() {
    alert(that.name);
  };
};

var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad

dimostrazione

La soluzione di cui sopra volontà assing thisper thatpoi possiamo e l'accesso alla proprietà nome all'interno del sayHimetodo da that, quindi questo può essere chiamato senza problemi all'interno della chiamata DOM.

Un'altra soluzione è quella di assegnare un thatoggetto vuoto e aggiungere proprietà e metodi ad esso e quindi restituirlo. Ma con questa soluzione hai perso il valore prototypedel costruttore.

var Person = function(name) {
  var that = {};
  that.name = name;
  that.sayHi = function() {
    alert(that.name);
  };
  return that;
};

2

Ecco un esempio `

$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();

            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                    var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'. 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

Quindi puoi vedere che il valore di questo è due valori diversi a seconda dell'elemento DOM che scegli come target ma quando aggiungi "quello" al codice sopra cambi il valore di "questo" che stai prendendo di mira.

`$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();
            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                var that = this;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                   ***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
                    var imgAlt = $(this).find('img').attr('alt'); 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

..... $ (that) .css ("background-color", "# ffe700"); // Qui il valore di "that" è ".our-work-group> p> a" perché il valore di var that = this; quindi anche se ci troviamo in "this" = '.our-work-single-page', possiamo comunque usare "that" per manipolare il precedente elemento DOM.

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.