Differenza tra questo e self in JavaScript


118

Tutti sono a conoscenza di thisjavascript, ma ci sono anche casi di selfincontrati in natura, come qui

Allora, qual è la differenza tra thise selfin JavaScript?



8
@dystroy: ce n'è uno: window.self( === window). Sebbene l'OP probabilmente significhi un nome di variabile banale ...
Bergi

2
@dystroy: In realtà non pensavo che potesse davvero pensarlo, ma in effetti in ambito globale (e in un ambiente browser) this === selfè vero :-)
Bergi

2
Soggettivo a parte: l'aliasing thisto selfnon è una grande pratica al giorno d'oggi quando è comune avere codice con molti (beh, più di uno è abbastanza brutto) livelli di annidamento di callback, come conseguenza della programmazione asincrona. Utilizza invece un nome più descrittivo. Oggettivamente parlando il nome thisstesso non contiene informazioni ed è solo una scelta non cattiva del nome perché il contesto lessicale di una definizione di classe lo qualifica.
millimoose

2
questa è una domanda valida e utile, dovrebbe essere riaperta
danza

Risposte:


127

A meno che non sia impostato altrove, il valore di selfè windowperché JavaScript ti consente di accedere a qualsiasi proprietà xdi windowsemplicemente x, invece di window.x. Pertanto, selfè davvero window.self, che è diverso da this.

window.self === window; // true

Se stai usando una funzione che viene eseguita nell'ambito globale e non è in modalità rigorosa, il thisvalore predefinito è windowe quindi

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

Se stai usando una funzione in un contesto diverso, thisfarà riferimento a quel contesto, ma lo selfsarà comunque window.

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

Puoi trovare le window.selfdefinizioni nella bozza di lavoro del W3C 2006 per l' oggetto Finestra qui .


34
Per completezza, selfè utile nel contesto di WebWorker quando la finestra non è accessibile ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Usare selfinvece di windowti permette di accedere all'oggetto globale in modo portatile.
lqc

24

Una leggera aggiunta a questo dato che le persone potrebbero riscontrarlo nel contesto dei lavoratori dei servizi, nel qual caso significa qualcosa di leggermente diverso.

Potresti vederlo in un modulo di service worker:

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

In questo caso self si riferisce a WorkerGlobalScope e questo è il metodo standard per l'impostazione dei listener di eventi.

Dai documenti di Mozilla :

Utilizzando self, è possibile fare riferimento all'ambito globale in un modo che funzionerà non solo in un contesto di finestra (self si risolverà in window.self) ma anche in un contesto di lavoro (self si risolverà quindi in WorkerGlobalScope.self).


Grazie ! Stavo cercando questa risposta :)
agpt

23

Anche se sono in ritardo qui, mi sono imbattuto in un esempio che anch'esso può essere utile per capire thisulteriormente:

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

OPERAZIONE

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

Prima di ECMA 5, thisnella funzione interna si faceva riferimento all'oggetto finestra globale; mentre, a partire da ECMA 5, thisnella funzione interna sarebbe indefinita.


questo è sempre definito nel suo contesto. Ciò che è indefinito è this.foo. Questa è un'enorme differenza e per ottenere il comportamento che hai menzionato esisteva prima di ECMA 5, le funzioni freccia possono essere utilizzate o come hai specificato assegnando il sé come esterno alla funzione interna e usando il sé all'interno invece di questo, il modo più pulito è la funzione freccia .
Dejazmach

2

Il riferimento all'ECMA 5 deve essere chiarito.

Presumo che significhi ECMA-262 Edizione 5. Va notato che ECMA-262 (noto anche come ECMAScript o, meno precisamente, Javascript) è un linguaggio di scripting generale che è stato implementato nei browser Internet. Dallo standard Edition 5.1:

I seguenti passaggi vengono eseguiti quando il controllo entra nel contesto di esecuzione per il codice funzione contenuto nell'oggetto funzione F, un chiamante ha fornito thisArg e un chiamante ha fornito argumentsList:

  1. Se il codice della funzione è un codice rigoroso, impostare ThisBinding su thisArg.
  2. Altrimenti, se thisArg è null o undefined, impostare ThisBinding sull'oggetto globale.
  3. Altrimenti, se Type (thisArg) non è Object, impostare ThisBinding su ToObject (thisArg).
  4. Altrimenti imposta ThisBinding su thisArg
  5. ... (non su "questo")

Il termine "oggetto globale" si riferisce a qualsiasi oggetto si trovi all'inizio della catena dell'ambito. Per i browser questo sarebbe l'oggetto "finestra" ma questa è una scelta di implementazione (Windows Script Host ha un oggetto globale invisibile ma nessuna modalità rigorosa, quindi i riferimenti non qualificati accedono alle sue proprietà e non esiste un "sé" globale). Inoltre, la "modalità rigorosa" deve essere abilitata esplicitamente altrimenti non è attiva (sezione 14.1 dello standard). In quanto tale, un "this" non definito sarebbe comunque risolto nell'oggetto globale (finestra) in "ECMA 5" con la modalità rigorosa non attiva.

Quindi la risposta alla domanda è:

"questo" si riferisce sempre all'oggetto che richiama la funzione. Se la funzione non è stata invocata da un oggetto (cioè non una chiamata a un metodo), "this" (come passato alla funzione) è "undefined". Tuttavia, se NON si utilizza la modalità rigorosa, un "questo" non definito viene impostato sull'oggetto globale (regola 2 sopra).

"sé" non ha un significato sintattico speciale, è solo un identificatore. I browser tendono a definire window.self (solo una proprietà dell'oggetto finestra globale) = window. Ciò si traduce in riferimenti non qualificati a "self" che sono uguali a "finestra" A MENO CHE "self" non sia stato ridefinito all'interno di un ambito di chiusura (come da "var self = this;" sopra. Buona fortuna ridefinendo "this".)

Quindi la spiegazione completa dell'esempio sopra è:

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"

Una variazione interessante dell'esempio crea una chiusura restituendo un riferimento alla funzione interna.

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

Produrre

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

Nota come la funzione interna non viene chiamata fino a quando non viene invocata da yourObject. Quindi this.foo è ora yourObject.foo ma self si risolve ancora nella variabile nello scope di inclusione che, nel momento in cui è stato restituito l'oggetto funzione interna, era (e nella chiusura risultante è ancora) myObject. Quindi, all'interno della funzione interna, "questo" si riferisce all'oggetto che chiama la funzione interna mentre "sé" si riferisce all'oggetto che ha chiamato la funzione esterna per creare il riferimento alla funzione interna.

Per riassumere il sommario del sommario, "questo" è definito dallo standard del linguaggio, "self" è definito da chi lo definisce (implementatore runtime o programmatore finale).


0

Di seguito sono riportate alcune combinazioni di output della console "window", "self" e "this" nell'ambito globale (ambiente browser) per vedere dove si riferisce.

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