Różnica między tym a sobą w JavaScript


118

Każdy jest tego świadomy thisw javascript, ale są też przypadki selfnapotkanych na wolności, takich jak tutaj

Jaka jest więc różnica między językiem JavaScript thisi selfw nim?



8
@dystroy: Jest jeden: window.self( === window). Chociaż OP prawdopodobnie oznacza trywialną nazwę zmiennej…
Bergi

2
@dystroy: Właściwie nie sądziłem, że naprawdę może to mieć na myśli, ale rzeczywiście w zakresie globalnym (i środowiska przeglądarki) this === selfjest to prawdą :-)
Bergi

2
Subiektywne na bok: aliasing thisdo selfnie jest obecnie dobrą praktyką, gdy powszechne jest posiadanie kodu z wieloma (no cóż, więcej niż jeden jest wystarczająco zły) poziomami zagnieżdżania wywołań zwrotnych, jako konsekwencja programowania asynchronicznego. Zamiast tego użyj bardziej opisowej nazwy. Obiektywnie rzecz biorąc, thissama nazwa nie zawiera żadnych informacji i jest jedynie niezłomym wyborem nazwy, ponieważ kwalifikuje ją kontekst leksykalny definicji klasy.
millimoose

2
jest to ważne i przydatne pytanie, należy je ponownie otworzyć
danza

Odpowiedzi:


127

Chyba ustawić w innym miejscu, wartość selfjest windowponieważ JavaScript umożliwia dostęp do wszelkich nieruchomości xo windowtak po prostu x, zamiast window.x. Dlatego selfjest naprawdę window.self, co różni się od this.

window.self === window; // true

Jeśli używasz funkcji, która jest wykonywana w zakresie globalnym i nie jest w trybie ścisłym, thisdomyślnie jest to window, a zatem

function foo() {
    console.log(
        window.self === window, // is self window?
        window.self === this,   // is self this?
        this === window         // is this window?
    );
}
foo(); // true true true

Jeśli używasz funkcji w innym kontekście, thisbędzie odnosić się do tego kontekstu, ale selfnadal będzie window.

// invoke foo with context {}
foo.call({}); // true false false

Możesz znaleźć window.selfdefinicję w roboczej wersji roboczej W3C 2006 dla obiektu okna tutaj .


34
Dla kompletności, selfjest przydatne w kontekście WebWorker, gdy okno nie jest dostępne ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/ ... ). Używanie selfzamiast windowumożliwia dostęp do obiektu globalnego w sposób przenośny.
lqc

24

Niewielki dodatek do tego, ponieważ ludzie mogą się z tym spotkać w kontekście pracowników usług, w którym to przypadku oznacza to coś nieco innego.

Możesz zobaczyć to w module Service Worker:

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
});

Tutaj self odnosi się do WorkerGlobalScope i jest to standardowa metoda ustawiania detektorów zdarzeń.

Z dokumentów Mozilli :

Używając self, możesz odwoływać się do zakresu globalnego w sposób, który będzie działał nie tylko w kontekście okna (self rozwiąże się do window.self), ale także w kontekście roboczym (self rozwiąże się wtedy do WorkerGlobalScope.self).


Dzięki ! Szukałem tej odpowiedzi :)
agpt

23

Chociaż jestem spóźniony, ale natknąłem się na jeden przykład, który również może być pomocny w zrozumieniu this:

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    (function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    }());
  }
};
myObject.func();

O / P

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

Przed ECMA 5 thisfunkcja wewnętrzna odwoływała się do globalnego obiektu okna; podczas gdy od ECMA 5 thisfunkcja wewnętrzna byłaby nieokreślona.


jest to zawsze definiowane w swoim kontekście. Niezdefiniowane jest this.foo. To ogromna różnica i aby osiągnąć zachowanie, o którym wspomniałeś, istniało przed ECMA 5, można użyć funkcji strzałkowych lub, jak określiłeś, przypisując self do tego poza funkcją wewnętrzną i używając zamiast tego self wewnątrz, a bardziej przejrzystym sposobem jest funkcja strzałkowa .
Dejazmach

2

Odniesienie do ECMA 5 wymaga wyjaśnienia.

Zakładam, że oznacza to ECMA-262 wydanie 5. Należy zauważyć, że ECMA-262 (aka ECMAScript lub mniej dokładnie Javascript) jest ogólnym językiem skryptowym, który został zaimplementowany w przeglądarkach internetowych. Ze standardu Edition 5.1:

Poniższe kroki są wykonywane, gdy sterowanie wchodzi w kontekst wykonania dla kodu funkcji zawartego w obiekcie funkcji F, obiekt wywołujący podał thisArg i obiekt wywołujący podany argumentsList:

  1. Jeśli kod funkcji jest kodem ścisłym, ustaw ThisBinding na thisArg.
  2. W przeciwnym razie, jeśli thisArg ma wartość null lub undefined, ustaw ThisBinding na obiekt globalny.
  3. W przeciwnym razie, jeśli Type (thisArg) nie jest Object, ustaw ThisBinding na ToObject (thisArg).
  4. W przeciwnym razie ustaw ThisBinding na thisArg
  5. ... (nie o „tym”)

Termin „obiekt globalny” odnosi się do dowolnego obiektu znajdującego się na początku łańcucha zasięgu. W przypadku przeglądarek byłby to obiekt „window”, ale jest to wybór implementacji (Host skryptów systemu Windows ma niewidoczny obiekt globalny, ale nie ma trybu ścisłego, więc niekwalifikowane odwołania mają dostęp do jego właściwości i nie ma globalnego „własnego”). Ponadto „tryb ścisły” musi być jawnie włączony, w przeciwnym razie nie będzie aktywny (sekcja 14.1 normy). W związku z tym nieokreślone „this” nadal rozwiązywałoby się do obiektu globalnego (okna) w „ECMA 5” z nieaktywnym trybem ścisłym.

Tak więc odpowiedź na pytanie brzmi:

„this” zawsze odnosi się do obiektu wywołującego funkcję. Jeśli funkcja nie została wywołana przez obiekt (tj. Nie została wywołana metoda), wówczas „this” (przekazane do funkcji) jest „niezdefiniowane”. Jednakże, jeśli NIE używasz trybu ścisłego, to niezdefiniowane „this” jest ustawiane na obiekt globalny (zasada 2 powyżej).

„Ja” nie ma specjalnego znaczenia składniowego, jest tylko identyfikatorem. Przeglądarki mają tendencję do definiowania window.self (tylko właściwość globalnego obiektu window) = window. Powoduje to, że niekwalifikowane odniesienia do „self” są tym samym, co „okno”, chyba że „self” zostało przedefiniowane w ramach obejmującego zakresu (na przykład przez „var self = this;” powyżej. Powodzenia w ponownym definiowaniu „this”).

Zatem pełne wyjaśnienie powyższego przykładu jest następujące:

outer func:  this.foo = bar
// "this" refers to the invoking object "myObject"
outer func:  self.foo = bar
// "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject"
inner func:  this.foo = undefined
// "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined.
inner func:  self.foo = bar
// self resolves to the variable in the enclosing scope which is still "myObject"

Ciekawa odmiana przykładu tworzy zamknięcie, zwracając odwołanie do funkcji wewnętrznej.

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    return function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    };
  }
};
var yourObject = {
 foo: "blat",
 func: myObject.func() // function call not function object
};
console.log("----");
yourObject.func();

Produkujemy

outer func:  this.foo = bar
outer func:  self.foo = bar
----
inner func:  this.foo = blat
inner func:  self.foo = bar

Zwróć uwagę, że funkcja wewnętrzna nie jest wywoływana, dopóki nie zostanie wywołana przez yourObject. Więc this.foo to teraz yourObject.foo, ale self nadal jest rozpoznawane jako zmienna w otaczającym zakresie, która w momencie zwrócenia wewnętrznego obiektu funkcji była (iw wynikowym zamknięciu nadal jest) myObject. Zatem w ramach funkcji wewnętrznej „this” odnosi się do obiektu wywołującego funkcję wewnętrzną, podczas gdy „self” odnosi się do obiektu, który wywołał funkcję zewnętrzną, aby utworzyć odniesienie do funkcji wewnętrznej.

Podsumowując podsumowanie podsumowania, „this” jest zdefiniowane przez standard języka, „self” jest definiowane przez tego, kto je definiuje (realizator wykonawczy lub programista końcowy).


0

Znajdź poniżej kilka kombinacji danych wyjściowych konsoli „window”, „self” i „this” w zakresie globalnym (środowisko przeglądarki), aby zobaczyć, do czego się odnosi.

console.log( window ); // Window {…}
console.log( self );   // Window {…}
console.log( this );   // Window {…}

console.log( window.window ); // Window {…}
console.log( window.self );   // Window {…}
console.log( window.this );   // undefined  

console.log( self.self );     // Window {…}
console.log( self.window );   // Window {…}
console.log( self.this );     // undefined

console.log( this.this );     // undefined
console.log( this.window );   // Window {…}
console.log( this.self );     // Window {…}

console.log( window.window.window );    // Window {…}
console.log( self.self.self );          // Window {…}
console.log( window.self.window.self ); // Window {…}
console.log( self.window.self.window ); // Window {…}
console.log( this.this );               // undefined
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.