Unterschied zwischen diesem und sich selbst in JavaScript

118

Jeder kennt thisJavascript, aber es gibt auch Fälle, in selfdenen man in freier Wildbahn vorkommt, wie hier

Was ist der Unterschied zwischen thisund selfin JavaScript?

Ben Nelson
quelle
3
Und diesbezüglich ...
Denys Séguret
8
@dystroy: Es gibt eine: window.self( === window). Obwohl das OP wahrscheinlich einen trivialen Variablennamen bedeutet…
Bergi
2
@dystroy: Eigentlich hätte ich nicht gedacht, dass er es wirklich so meinen könnte, aber in der Tat ist im globalen Bereich (und einer Browser-Umgebung) this === selfwahr :-)
Bergi
2
Abgesehen von subjektiven Aspekten: Aliasing thisauf selfist heutzutage keine gute Praxis, wenn es als Folge der asynchronen Programmierung üblich ist, Code mit vielen (naja, mehr als eine ist schlecht genug) Ebenen der Rückrufverschachtelung zu haben. Verwenden Sie stattdessen einen aussagekräftigeren Namen. Objektiv gesehen enthält der Name thisselbst keine Informationen und ist nur eine nicht schlechte Wahl des Namens, da der lexikalische Kontext einer Klassendefinition ihn qualifiziert.
Millimoose
2
Dies ist eine gültige und nützliche Frage, sie sollte wieder geöffnet werden
Danza

Antworten:

126

Es sei denn , an anderer Stelle gesetzt, der Wert selfist , windowweil JavaScript Ermöglicht den Zugriff auf eine beliebige Eigenschaft xvon windowals einfach x, statt window.x. Daher selfist wirklich window.self, was anders ist als this.

window.self === window; // true

Wenn Sie eine Funktion verwenden, die im globalen Bereich ausgeführt wird und sich nicht im strengen Modus befindet, wird thisstandardmäßig windowund daher verwendet

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

Wenn Sie eine Funktion in einem anderen Kontext verwenden, thiswird auf diesen Kontext verwiesen, dies wird jedoch selfweiterhin der Fall sein window.

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

Eine window.selfDefinition im W3C 2006-Arbeitsentwurf für das Fensterobjekt finden Sie hier .

Paul S.
quelle
34
Der Vollständigkeit selfhalber ist dies im Kontext von WebWorker nützlich, wenn auf das Fenster nicht zugegriffen werden kann ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Mit selfanstelle von windowkönnen Sie auf tragbare Weise auf das globale Objekt zugreifen.
lqc
24

Eine geringfügige Ergänzung, da dies im Zusammenhang mit Servicemitarbeitern auftreten kann. In diesem Fall bedeutet dies etwas anderes.

Möglicherweise wird dies in einem Service Worker-Modul angezeigt:

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

Hier bezieht sich self auf das WorkerGlobalScope, und dies ist die Standardmethode zum Festlegen von Ereignis-Listenern.

Aus Mozilla-Dokumenten :

Wenn Sie self verwenden, können Sie auf den globalen Bereich so verweisen, dass er nicht nur in einem Fensterkontext funktioniert (self wird in window.self aufgelöst), sondern auch in einem Worker-Kontext (self wird dann in WorkerGlobalScope.self aufgelöst).

andyhasit
quelle
Vielen Dank ! Ich habe nach dieser Antwort gesucht :)
agpt
23

Ich bin zwar zu spät hier, aber ich bin auf ein Beispiel gestoßen, das ebenfalls hilfreich sein kann, um es besser zu verstehen 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

Vor ECMA 5 thiswürde sich die innere Funktion auf das globale Fensterobjekt beziehen; Ab ECMA 5 thiswäre die innere Funktion undefiniert.

Shashank Vivek
quelle
Dies wird immer in seinem Kontext definiert. Was undefiniert ist, ist this.foo. Das ist ein großer Unterschied, und um das von Ihnen erwähnte Verhalten zu erreichen, das vor ECMA 5 existierte, können Pfeilfunktionen verwendet werden oder wie Sie angegeben haben, sich selbst als außerhalb der inneren Funktion zuzuweisen und stattdessen selbst innerhalb zu verwenden, wobei der sauberere Weg die Pfeilfunktion ist .
Dejazmach
1

Der Verweis auf ECMA 5 muss präzisiert werden.

Ich gehe davon aus, dass dies ECMA-262 Edition 5 bedeutet. Es sollte beachtet werden, dass ECMA-262 (auch bekannt als ECMAScript oder weniger genau Javascript) eine allgemeine Skriptsprache ist, die in Internetbrowsern implementiert wurde. Ab dem Standard Edition 5.1:

Die folgenden Schritte werden ausgeführt, wenn die Steuerung in den Ausführungskontext für den im Funktionsobjekt F enthaltenen Funktionscode eintritt, ein Aufrufer dieses Argument bereitstellt und ein Aufrufer die Argumentliste bereitstellt:

  1. Wenn der Funktionscode ein strikter Code ist, setzen Sie ThisBinding auf thisArg.
  2. Andernfalls setzen Sie die ThisBinding auf das globale Objekt, wenn thisArg null oder undefiniert ist.
  3. Andernfalls, wenn Type (thisArg) kein Object ist, setzen Sie ThisBinding auf ToObject (thisArg).
  4. Andernfalls setzen Sie ThisBinding auf thisArg
  5. ... (nicht über "das")

Der Begriff "globales Objekt" bezieht sich auf jedes Objekt, das sich am Anfang der Bereichskette befindet. Für Browser wäre dies das "Fenster" -Objekt, dies ist jedoch eine Implementierungsoption (Windows Script Host hat ein unsichtbares globales Objekt, aber keinen strengen Modus, sodass unqualifizierte Referenzen auf seine Eigenschaften zugreifen und es kein globales "Selbst" gibt). Außerdem muss der "strikte Modus" explizit aktiviert werden, da er sonst nicht aktiv ist (Abschnitt 14.1 des Standards). Als solches würde ein undefiniertes "dies" immer noch in das globale Objekt (Fenster) in "ECMA 5" aufgelöst, wobei der strikte Modus nicht aktiv ist.

Die Antwort auf die Frage lautet also:

"this" bezieht sich immer auf das Objekt, das die Funktion aufruft. Wenn die Funktion nicht von einem Objekt aufgerufen wurde (dh kein Methodenaufruf), ist "this" (wie an die Funktion übergeben) "undefined". Wenn jedoch NICHT der strikte Modus verwendet wird, wird ein undefiniertes "dies" auf das globale Objekt gesetzt (Regel 2 oben).

"self" hat keine spezielle syntaktische Bedeutung, es ist nur eine Kennung. Browser neigen dazu, window.self (nur eine Eigenschaft des globalen Fensterobjekts) = window zu definieren. Dies führt dazu, dass uneingeschränkte Verweise auf "Selbst" dasselbe sind wie "Fenster", WENN "Selbst" in einem umschließenden Bereich neu definiert wurde (z. B. durch "var self = this;" oben. Viel Glück beim Neudefinieren von "this".)

Die vollständige Erklärung des obigen Beispiels lautet also:

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"

Eine interessante Variation des Beispiels erzeugt einen Abschluss, indem ein Verweis auf die innere Funktion zurückgegeben wird.

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

Produzieren

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

Beachten Sie, dass die innere Funktion erst aufgerufen wird, wenn Sie von yourObject aufgerufen werden. Also ist this.foo jetzt yourObject.foo, aber self wird immer noch in die Variable im umschließenden Bereich aufgelöst, die zum Zeitpunkt der Rückgabe des inneren Funktionsobjekts myObject war (und in der resultierenden Schließung immer noch ist). Innerhalb der inneren Funktion bezieht sich "dies" auf das Objekt, das die innere Funktion aufruft, während sich "self" auf das Objekt bezieht, das die äußere Funktion aufgerufen hat, um den Verweis auf die innere Funktion zu erstellen.

Um die Zusammenfassung der Zusammenfassung zusammenzufassen, wird "dies" durch den Sprachstandard definiert, "selbst" wird durch denjenigen definiert, der sie definiert (Laufzeitimplementierer oder Endprogrammierer).

Uber Kluger
quelle
0

Nachfolgend finden Sie einige Kombinationen der Konsolenausgaben "Fenster", "Selbst" und "Diese" im globalen Bereich (Browserumgebung), um zu sehen, auf was sie sich beziehen.

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
SridharKritha
quelle