Diferencia entre esto y uno mismo en JavaScript

118

Todo el mundo lo conoce thisen javascript, pero también hay casos selfen los que se encuentran en la naturaleza, como aquí.

Entonces, ¿cuál es la diferencia entre thisy selfen JavaScript?

Ben Nelson
fuente
3
Y con respecto a esto ...
Denys Séguret
8
@dystroy: Hay uno: window.self( === window). Aunque el OP probablemente significa un nombre de variable trivial…
Bergi
2
@dystroy: En realidad, no pensé que realmente pudiera decirlo en serio, pero de hecho en el alcance global (y un entorno de navegador) this === selfes cierto :-)
Bergi
2
Subjetiva de lado: aliasing thisa selfno es una gran práctica hoy en día cuando es común que tiene código con muchos (bueno, más de uno es bastante malo) niveles de anidamiento de devolución de llamada, como consecuencia de la programación asincrónica. En su lugar, utilice un nombre más descriptivo. Hablando objetivamente, el nombre en thissí mismo no contiene información y es solo una mala elección de nombre porque el contexto léxico de una definición de clase lo califica.
millimoose
2
esta es una pregunta válida y útil, debe ser reabierta
danza

Respuestas:

127

A menos que se establezca en otro lugar, el valor de selfes windowporque JavaScript le permite acceder a cualquier propiedad xde windowsimplemente x, en lugar de window.x. Por lo tanto, selfes realmente window.self, que es diferente a this.

window.self === window; // true

Si está utilizando una función que se ejecuta en el ámbito global y no está en modo estricto, el valor thispredeterminado es window, y por lo tanto

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

Si está utilizando una función en un contexto diferente, thisse referirá a ese contexto, pero selfseguirá siendo así window.

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

Puede encontrar window.selfdefinido en el borrador de trabajo del W3C 2006 para el Objeto Ventana aquí .

Paul S.
fuente
34
Para completar, selfes útil en el contexto de WebWorker cuando no se puede acceder a la ventana ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Usar en selflugar de le windowpermite acceder al objeto global de forma portátil.
lqc
24

Una pequeña adición a esto, ya que las personas pueden encontrar esto en el contexto de los trabajadores de servicios, en cuyo caso significa algo ligeramente diferente.

Es posible que vea esto en un módulo de trabajador de servicio:

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

Aquí self se refiere a WorkerGlobalScope, y este es el método estándar para configurar los detectores de eventos.

De los documentos de Mozilla :

Al usar self, puede hacer referencia al alcance global de una manera que funcionará no solo en un contexto de ventana (self se resolverá en window.self) sino también en un contexto de trabajador (self luego se resolverá en WorkerGlobalScope.self).

andyhasit
fuente
Gracias ! Estaba buscando esta respuesta :)
agpt
23

Aunque llego tarde aquí, encontré un ejemplo que también puede ser útil para comprender mejor 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

Antes de ECMA 5, thisen la función interna se referiría al objeto de ventana global; mientras que, a partir de ECMA 5, thisla función interna sería indefinida.

Shashank Vivek
fuente
esto siempre se define en su contexto. Lo que no está definido es esto. Foo. Esa es una gran diferencia y para lograr el comportamiento que mencionó que existía antes de ECMA 5, se pueden usar las funciones de flecha o, como especificó, asignarse a sí mismo para estar fuera de la función interna y usar sí mismo adentro en lugar de esto, la forma más limpia es la función de flecha .
Dejazmach
2

Es necesario aclarar la referencia a ECMA 5.

Supongo que significa ECMA-262 Edición 5. Cabe señalar que ECMA-262 (también conocido como ECMAScript o, menos exactamente, Javascript) es un lenguaje de programación general que se ha implementado en los navegadores de Internet. Del estándar Edition 5.1:

Los siguientes pasos se llevan a cabo cuando el control ingresa al contexto de ejecución para el código de función contenido en el objeto de función F, un llamador proporcionó thisArg y un llamador proporcionó argumentosList:

  1. Si el código de función es un código estricto, establezca ThisBinding en thisArg.
  2. De lo contrario, si thisArg es nulo o no está definido, establezca ThisBinding en el objeto global.
  3. De lo contrario, si Type (thisArg) no es Object, establezca ThisBinding en ToObject (thisArg).
  4. De lo contrario, establezca ThisBinding en thisArg
  5. ... (no sobre "esto")

El término "objeto global" se refiere a cualquier objeto que se encuentre en la parte superior de la cadena de alcance. Para los navegadores, este sería el objeto "ventana", pero esta es una opción de implementación (Windows Script Host tiene un objeto global invisible pero no un modo estricto, por lo que las referencias no calificadas acceden a sus propiedades y no hay un "yo" global). Además, el "modo estricto" debe habilitarse explícitamente; de ​​lo contrario, no estará activo (sección 14.1 del estándar). Como tal, un "esto" no definido todavía se resolvería en el objeto global (ventana) en "ECMA 5" con el modo estricto no activo.

Entonces la respuesta a la pregunta es:

"esto" siempre se refiere al objeto que invoca la función. Si la función no fue invocada por un objeto (es decir, no una llamada a un método), entonces "esto" (como se le pasó a la función) es "indefinido". Sin embargo, si NO usa el modo estricto, entonces un "esto" no definido se establece en el objeto global (regla 2 anterior).

"self" no tiene un significado sintáctico especial, es solo un identificador. Los navegadores tienden a definir window.self (solo una propiedad del objeto de ventana global) = window. Esto da como resultado referencias incondicionales de que "self" es lo mismo que "window" A MENOS QUE "self" se haya redefinido dentro de un ámbito adjunto (como por ejemplo, "var self = this;" arriba. Buena suerte redefiniendo "this").

Entonces, la explicación completa del ejemplo anterior es:

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 variación interesante del ejemplo crea un cierre al devolver una referencia a la función 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();

Productor

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

Tenga en cuenta que la función interna no se llama hasta que la invoca yourObject. Entonces this.foo ahora es yourObject.foo pero self todavía se resuelve en la variable en el ámbito adjunto que, en el momento en que se devolvió el objeto de función interna, era (y en el cierre resultante todavía es) myObject. Entonces, dentro de la función interna, "esto" se refiere al objeto que llama a la función interna mientras que "self" se refiere al objeto que llamó a la función externa para crear la referencia a la función interna.

Para resumir el resumen del resumen, "esto" está definido por el estándar del lenguaje, "self" lo define quien lo define (implementador de tiempo de ejecución o programador final).

Uber Kluger
fuente
0

Encuentre a continuación algunas combinaciones de las salidas de la consola 'ventana', 'self' y 'this' en el ámbito global (entorno del navegador) para ver a dónde se refiere.

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
fuente