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?


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.


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


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ł.


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

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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.