Différence entre ceci et soi en JavaScript


118

Tout le monde est au courant de thisjavascript, mais il existe également des exemples de selfrencontrés dans la nature, comme ici

Alors, quelle est la différence entre thiset selfen JavaScript?



8
@dystroy: Il y en a un: window.self( === window). Bien que l'OP signifie probablement un nom de variable trivial…
Bergi

2
@dystroy: En fait, je ne pensais pas qu'il pouvait vraiment le dire, mais en effet, à l'échelle mondiale (et dans un environnement de navigateur), this === selfc'est vrai :-)
Bergi

2
SUBJECTIFS côté: aliasing thisà selfn'est pas une grande pratique de nos jours quand il est courant d'avoir un code avec beaucoup (bien, plus d'un est assez mauvais) niveaux d'imbrication de rappel, en conséquence de la programmation asynchrone. Utilisez plutôt un nom plus descriptif. Objectivement parlant, le nom thislui-même ne porte aucune information et n'est qu'un mauvais choix de nom parce que le contexte lexical d'une définition de classe le qualifie.
millimoose

2
c'est une question valide et utile, elle devrait être rouverte
danza

Réponses:


127

Sauf indication contraire, la valeur de selfest windowparce que JavaScript vous permet d'accéder à n'importe quelle propriété xde windowaussi simplement que xde window.x. Par conséquent, selfest vraiment window.self, ce qui est différent de this.

window.self === window; // true

Si vous utilisez une fonction qui est exécutée dans la portée globale et qui n'est pas en mode strict, la valeur par thisdéfaut est window, et donc

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 vous utilisez une fonction dans un contexte différent, thisfera référence à ce contexte, mais le selfsera toujours window.

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

Vous pouvez trouver window.selfdéfini dans le brouillon de travail du W3C 2006 pour l' objet Fenêtre ici .


34
Par selfsouci d' exhaustivité, est utile dans le contexte de WebWorker lorsque la fenêtre n'est pas accessible ( developer.mozilla.org/en-US/docs/Web/Guide/Performance/… ). Utiliser selfau lieu de windowvous permet d'accéder à l'objet global de manière portable.
lqc

24

Un léger ajout à cela, car les gens peuvent rencontrer cela dans le contexte des travailleurs des services, auquel cas cela signifie quelque chose de légèrement différent.

Vous pouvez voir ceci dans un module de service worker:

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

Ici, self fait référence au WorkerGlobalScope, et c'est la méthode standard pour définir les écouteurs d'événements.

À partir de la documentation Mozilla :

En utilisant self, vous pouvez faire référence à la portée globale d'une manière qui fonctionnera non seulement dans un contexte de fenêtre (self se résoudra en window.self) mais également dans un contexte de travail (self se résoudra alors en WorkerGlobalScope.self).


Merci ! Je cherchais cette réponse :)
agpt

23

Bien que je sois en retard ici, je suis tombé sur un exemple qui peut également être utile pour mieux comprendre 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

Avant ECMA 5, thisdans la fonction interne ferait référence à l'objet de fenêtre global; alors que, à partir de l'ECMA 5, thisla fonction interne ne serait pas définie.


ceci est toujours défini dans son contexte. Ce qui n'est pas défini, c'est this.foo. C'est une énorme différence et pour obtenir le comportement que vous avez mentionné existait avant ECMA 5, les fonctions fléchées peuvent être utilisées ou, comme vous l'avez spécifié, en attribuant à soi-même à l'extérieur de la fonction intérieure et en utilisant soi-même à l'intérieur au lieu de cela, la manière la plus propre étant la fonction flèche .
Dejazmach le

2

La référence à l'ECMA 5 doit être clarifiée.

Je suppose que cela signifie ECMA-262 Edition 5. Il convient de noter que ECMA-262 (aka ECMAScript ou, moins précisément, Javascript) est un langage de script général qui a été implémenté dans les navigateurs Internet. À partir de la norme Edition 5.1:

Les étapes suivantes sont effectuées lorsque le contrôle entre dans le contexte d'exécution du code de fonction contenu dans l'objet de fonction F, un appelant a fourni thisArg et un appelant a fourni argumentsList:

  1. Si le code de fonction est un code strict, définissez ThisBinding sur thisArg.
  2. Sinon, si thisArg est nul ou non défini, définissez ThisBinding sur l'objet global.
  3. Sinon, si Type (thisArg) n'est pas Object, définissez ThisBinding sur ToObject (thisArg).
  4. Sinon, définissez ThisBinding sur thisArg
  5. ... (pas à propos de "ceci")

Le terme «objet global» fait référence à tout objet qui se trouve en haut de la chaîne de portée. Pour les navigateurs, ce serait l'objet "window" mais c'est un choix d'implémentation (Windows Script Host a un objet global invisible mais pas de mode strict donc des références non qualifiées accèdent à ses propriétés et il n'y a pas de "self" global). De plus, le "mode strict" doit être explicitement activé sinon il n'est pas actif (section 14.1 de la norme). En tant que tel, un "this" non défini résoudrait toujours l'objet global (fenêtre) dans "ECMA 5" avec le mode strict non actif.

La réponse à la question est donc:

"this" fait toujours référence à l'objet qui appelle la fonction. Si la fonction n'a pas été invoquée par un objet (c'est-à-dire pas un appel de méthode), alors "this" (tel que passé à la fonction) est "indéfini". Cependant, si vous n'utilisez PAS le mode strict, un "this" non défini est défini sur l'objet global (règle 2 ci-dessus).

"self" n'a pas de signification syntaxique particulière, c'est juste un identifiant. Les navigateurs ont tendance à définir window.self (juste une propriété de l'objet global window) = window. Il en résulte que les références non qualifiées à «soi» sont identiques à «fenêtre» À MOINS QUE «soi» n'ait été redéfini dans une portée englobante (comme par «var self = this;» ci-dessus. Bonne chance pour redéfinir «this».)

L'explication complète de l'exemple ci-dessus est donc:

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"

Une variante intéressante de l'exemple crée une fermeture en renvoyant une référence à la fonction interne.

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

Produire

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

Notez que la fonction interne n'est pas appelée tant qu'elle n'est pas appelée par yourObject. Donc this.foo est maintenant yourObject.foo mais self se résout toujours à la variable dans la portée englobante qui, au moment où l'objet de la fonction interne a été renvoyé, était (et dans la fermeture résultante est toujours) myObject. Ainsi, dans la fonction interne, «ceci» fait référence à l'objet appelant la fonction interne tandis que «soi» se réfère à l'objet qui a appelé la fonction externe pour créer la référence à la fonction interne.

Pour résumer le résumé du résumé, «ceci» est défini par le standard du langage, «self» est défini par celui qui le définit (exécuteur ou programmeur final).


0

Trouvez ci-dessous quelques combinaisons de sorties de console 'window', 'self' et 'this' dans la portée globale (environnement de navigateur) pour voir où elles se réfèrent.

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.