118 votes

Pointeur Javascript "this" dans une fonction imbriquée

J'ai une question concernant le traitement du pointeur "this" dans un scénario de fonction imbriquée.

Supposons que j'insère l'exemple de code suivant dans une page web. J'obtiens une erreur lorsque j'appelle la fonction imbriquée "doSomeEffects()". J'ai vérifié dans Firebug et cela indique que lorsque je suis dans cette fonction imbriquée, le pointeur "this" pointe en fait vers l'objet global "window" - ce à quoi je ne m'attendais pas. Je ne dois pas avoir bien compris car je pensais que puisque j'avais déclaré la fonction imbriquée dans une fonction de l'objet, elle devait avoir une portée "locale" par rapport à la fonction (c'est-à-dire que le pointeur "this" devait se référer à l'objet lui-même, comme dans ma première instruction "if").

Toute indication (sans jeu de mots) serait appréciée.

var std_obj = {
  options : { rows: 0, cols: 0 },
  activeEffect : "none",
  displayMe : function() {

    // the 'this' pointer is referring to the std_obj
    if (this.activeEffect=="fade") { }

    var doSomeEffects = function() {

      // the 'this' pointer is referring to the window obj, why?
      if (this.activeEffect=="fade") { }

    }

    doSomeEffects();   
  }
};

std_obj.displayMe();

131voto

Kyle P Davis Points 578

En JavaScript, la fonction this dépend en fait de la manière dont vous faites vos appels de fonction.

En général, il y a trois façons de configurer le this objet :

  1. someThing.someFunction(arg1, arg2, argN)
  2. someFunction.call(someThing, arg1, arg2, argN)
  3. someFunction.apply(someThing, [arg1, arg2, argN])

Dans tous les exemples ci-dessus, le this sera someThing . L'appel d'une fonction sans l'objet parent principal vous donnera généralement la réponse suivante mondial ce qui, dans la plupart des navigateurs, signifie l'objet window objet.

63voto

Puisque cette question semble être l'une des plus votées dans son genre, permettez-moi d'ajouter, après toutes ces années, la solution ES6 utilisant des fonctions fléchées :

var std_obj = {
  ...
  displayMe() {
    ...
    var doSomeEffects = () => {
                        ^^^^^^^    ARROW FUNCTION    
      // In an arrow function, the 'this' pointer is interpreted lexically,
      // so it will refer to the object as desired.
      if (this.activeEffect=="fade") { }
    };
    ...    
  }
};

37voto

chuckj Points 7975

this ne fait pas partie de la portée de la fermeture, il peut être considéré comme un paramètre supplémentaire de la fonction qui est liée au site d'appel. Si la méthode n'est pas appelée en tant que méthode, l'objet global est transmis en tant que this . Dans le navigateur, l'objet global est identique à window . Par exemple, considérons la fonction suivante,

function someFunction() {
}

et l'objet suivant,

var obj = { someFunction: someFunction };

Si vous appelez la fonction en utilisant une syntaxe de méthode telle que,

obj.someFunciton();

puis this est lié à obj .

Si vous appelez directement someFunction(), comme par exemple,

someFunction();

puis this est lié à l'objet global, c'est-à-dire window .

La solution la plus courante consiste à capturer cette information dans la fermeture, par exemple,

displayMe : function() {      

    // the 'this' pointer is referring to the std_obj      
    if (this.activeEffect=="fade") { }      
    var that = this;  
    var doSomeEffects = function() {      

      // the 'this' pointer is referring to global
      // that, however, refers to the outscope this
      if (that.activeEffect=="fade") { }      
    }      

    doSomeEffects();         
 }

12voto

ronakshah725 Points 250

Pour comprendre cette question, essayez d'obtenir le résultat de l'extrait suivant

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

Le code ci-dessus affichera ce qui suit dans la console :

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

Dans la fonction externe, this et self font tous deux référence à myObject et peuvent donc tous deux référencer et accéder correctement à foo.

Dans la fonction interne, cependant, il ne s'agit plus de myObject. Par conséquent, this.foo est indéfini dans la fonction interne, alors que la référence à la variable locale self reste dans la portée et y est accessible. (Avant l'ECMA 5, this dans la fonction interne se référait à l'objet global de la fenêtre, alors qu'à partir de l'ECMA 5, this dans la fonction interne serait indéfini).

10voto

Shane Points 1011

Il y a une différence entre les variables d'enclos et "this". "This" est en fait défini par l'invocateur de la fonction, tandis que les variables explicites restent intactes à l'intérieur du bloc de déclaration de la fonction, connu sous le nom d'enceinte. Voir l'exemple ci-dessous :

function myFirstObject(){
    var _this = this;
    this.name = "myFirstObject";
    this.getName = function(){
       console.log("_this.name = " + _this.name + " this.name = " + this.name);  
    }
}

function mySecondObject(){
    var _this = this;
    this.name = "mySecondObject";
    var firstObject = new myFirstObject();
    this.getName = firstObject.getName
}

var secondObject = new mySecondObject();
secondObject.getName();

vous pouvez l'essayer ici : http://jsfiddle.net/kSTBy/

Ce qui se passe dans votre fonction, c'est que "doSomeEffects()" est appelé explicitement, ce qui signifie que le contexte ou le "ceci" de la fonction est la fenêtre. Si "doSomeEffects" était une méthode prototype, par exemple this.doSomeEffects sur disons "monObjet", alors myObject.doSomeEffects() ferait en sorte que "ceci" soit "monObjet".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X