Co oznacza „var that = this;” znaczy w JavaScript?

351

W pliku JavaScript widziałem:

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

Jaki jest cel zadeklarowania thati przypisania thistego do niego?

Chris
źródło
3
możliwy duplikat var self = this?
Bergi
6
Hack „ten” i „ten” nie jest wymagany dla funkcji strzałek. Z funkcjami strzałek „to” działa zgodnie z oczekiwaniami. Aby uzyskać więcej informacji, zobacz tutaj ES6. Głębokość: Funkcje strzałek
satguru srivastava
1
tutaj wyjaśniono tę koncepcję scotch.io/@alZami/understanding-this-in-javascript
AL-zami
Świetne wyjaśnienie tajemniczego zachowania na podstawie kontekstu tutaj
RBT
Najnowsze i zaktualizowane wyjaśnienie można znaleźć tutaj
Sukrit Gupta

Odpowiedzi:

485

Zacznę tę odpowiedź od ilustracji:

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
    });
});

Moja odpowiedź pierwotnie wykazała to za pomocą jQuery, który tylko nieznacznie się różni:

$('#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
    });
});

Ponieważ thisczęsto zmienia się po zmianie zakresu przez wywołanie nowej funkcji, nie można uzyskać dostępu do pierwotnej wartości za jej pomocą. Aliasing do thatpozwala nadal uzyskać dostęp do pierwotnej wartościthis .

Osobiście nie lubię używania thatjako aliasu. Rzadko jest oczywiste, do czego się odnosi, szczególnie jeśli funkcje są dłuższe niż kilka linii. I zawsze używać bardziej opisowego alias. W powyższych przykładach prawdopodobnie użyłbym clickedEl.

samotny dzień
źródło
149
Zwykle idę z var self = this;. Słowo thatwydaje się sugerować, że zmienna jest Cokolwiek, ALE this.
David Murdoch,
13
@David Tak, myślałem, że to trochę wprowadza w błąd. Ale jeśli, jak mówi Crockford, jest to konwencja, czy mądrze jest pójść tą drogą. Całkowicie się z tobą zgadzam, ma o wiele więcej sensu.
El Ronnoco
4
@ El Ronnoco, ale „Ma siwe włosy i spuchniętą brodę, a jego zachowanie przywodzi na myśl zrzędliwego starca, który krzyczy na dzieci, żeby zejść z trawnika”. - blogging.compendiumblog.com/blog/software-for-humans/0/0/… ;-p
David Murdoch
7
@ElRonnoco: To jednak apel do władzy. Jeśli kiedykolwiek zrobimy tylko to, co mówią „sławni ludzie”, powinniśmy zrobić katastrofę.
Wyścigi lekkości na orbicie
3
forEachFunkcji zajmuje drugi opcjonalny argument, który jest wiązanie funkcji. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);Tak więc należy dodać notatkę, która var that = thistak naprawdę nie jest potrzebna forEach.
Matt Clarkson
107

Z Crockford

Umownie, wykonujemy prywatny że zmiennej. Służy to do udostępnienia obiektu metodom prywatnym. Jest to obejście błędu w specyfikacji języka ECMAScript, który powoduje to być nieprawidłowo ustawione dla funkcji wewnętrznych.

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);

To ostrzega ...

Używa, że ​​to się nazywa Dave

Używa: Sądzi się, że nazywa się to niezdefiniowane

El Ronnoco
źródło
2
Dzięki, podsumowuje to wystarczająco dobrze dla mnie.
Chris
3
Przeczytałem to, nie rozumiem, ponieważ nie było żadnych szczegółów, szukałem w Google, znalazłem tę stronę. Gdzie znów wskazano mi to samo zdanie. Stąd opinia.
Aditya, poseł
3
To słuszna sprawa, powiedziałbym, że ktoś, kto nie zna JavaScript, miałby trudności z uchwyceniem tego pojęcia z samej mojej odpowiedzi. Odpowiedziałem bardzo krótko (i zamieściłem link do strony, dla której Googledeś ..) Powiedziałbym, że odpowiedź samotnego dnia jest najczystsza, chociaż nadal wolałabym to w prostym JS niż w przykładzie jQuery.
El Ronnoco
16
Nie obrażam się. Miło jest widzieć kogoś, kto komentuje podczas oddawania głosu!
El Ronnoco
4
Problem z odpowiedzią Crockforda polega na tym, że thatzmienna w ogóle nie jest użyta w jego przykładzie. Wygląda na to, że samo utworzenie zmiennej zmiennej thisma wpływ na resztę kodu.
r3m0t
86

To jest hack, aby funkcje wewnętrzne (funkcje zdefiniowane wewnątrz innych funkcji) działały bardziej tak, jak powinny. W javascript, gdy zdefiniujesz jedną funkcję w innej, thisautomatycznie ustawi się na zasięg globalny. Może to być mylące, ponieważ oczekuje thissię, że będzie miała taką samą wartość jak w funkcji zewnętrznej.

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();

};

Jest to szczególnie problem, gdy tworzysz funkcję jako metodę obiektu (jak car.startw przykładzie), a następnie tworzysz funkcję wewnątrz tej metody (jak activateStarter). W metodzie najwyższego poziomu thiswskazuje na obiekt, jest to metoda (w tym przypadku car), ale w funkcji wewnętrznejthis wskazuje teraz na zasięg globalny. To jest ból.

Utworzenie zmiennej do użycia zgodnie z konwencją w obu zakresach jest rozwiązaniem tego bardzo ogólnego problemu z javascript (chociaż jest także użyteczny w funkcjach jquery). Właśnie dlatego bardzo ogólna brzmiąca nazwathat używana jest . Jest to łatwo rozpoznawalna konwencja w przezwyciężaniu niedociągnięć w języku.

Jak El Ronnoco w Douglas Crockford uważa, że ​​to dobry pomysł.

Waylon Flinn
źródło
8
Podejrzewam, że jest to bardziej użyteczna odpowiedź niż zaakceptowana. Ponieważ wyjaśnia to powód, dla którego Crockford wynalazł „to”, podczas gdy odpowiedź na temat jQuery nie.
Konstantin Smolyanin
4
To jest rzeczywiście lepszy przykład niż zaakceptowana odpowiedź. Wyjaśnia, jak to jest „błąd w specyfikacji języka skryptowego ECMAS, który powoduje, że jest to niepoprawnie ustawione dla funkcji wewnętrznych”, powiedział Douglas.
kakacii
1
Możesz jednak poprawić gramatykę. Wiem, że to bardziej literówka, ale może pomylić początkujących javascript, ponieważ to pytanie jest bardziej dla początkujących. Mam na myśli, że powinno to być: var car = {}; car.starter = {}; car.start = function () {...}
kakacii
1
@kakacii Thanks. Naprawiono teraz.
Waylon Flinn
9

Użycie thatnie jest tak naprawdę konieczne, jeśli obejdziesz to za pomocą call()lub 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);
};
Adela
źródło
3

Czasami thismoże odnosić się do innego zakresu i odnosić się do czegoś innego, na przykład załóżmy, że chcesz wywołać metodę konstruktora wewnątrz zdarzenia DOM, w tym przypadkuthis odniesie się do elementu DOM, a nie do utworzonego obiektu.

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

Próbny

Rozwiązanie powyżej woli assing thisaby thatnastępnie możemy i mienia Nazwa dostępu wewnątrz sayHimetody zthat , tak to można nazwać bez problemów wewnątrz zaproszenia DOM.

Innym rozwiązaniem jest przypisanie pustego thatobiektu oraz dodanie do niego właściwości i metod, a następnie zwrócenie go. Ale dzięki temu rozwiązaniu straciłeś prototypekonstruktora.

var Person = function(name) {
  var that = {};
  that.name = name;
  that.sayHi = function() {
    alert(that.name);
  };
  return that;
};
Ahmad Ajmi
źródło
2

Oto przykład `

$(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();
                    }
                });
            }

        });
    });`

Możesz więc zobaczyć, że ta wartość to dwie różne wartości w zależności od elementu DOM, na który celujesz, ale dodając „to” do powyższego kodu, zmieniasz wartość „tego”, na który celujesz.

`$(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 („kolor tła”, „# ffe700”); // Tutaj wartością „tego” jest „.our-work-group> p> a”, ponieważ wartość var ​​that = this; więc mimo tego, że jesteśmy w „this” = '.our-work-single-page ”, nadal możemy użyć„ tego ”do manipulowania poprzednim elementem DOM.

stacksonstacksonstacks
źródło