Javascript: pourquoi "cela" dans la fonction privée se réfère à la portée globale?

Considérez le code suivant:

function A() {} A.prototype.go = function() { console.log(this); //A { go=function()} var f = function() { console.log(this); //Window }; f(); } var a = new A(); a.go(); 

Pourquoi '' cette 'dans la fonction' f 'se réfère à la portée globale? Pourquoi ce n'est pas la portée de la fonction 'A'?

JavaScript a un concept différent de ce que le nom spécial se réfère à la plupart des autres langages de programmation. Il existe exactement cinq façons différentes dans lesquelles la valeur de this peut être liée dans la langue.

La portée mondiale

 this; 

Lorsque vous utilisez this dans une portée globale, il se référera simplement à l'objet global .

Appel d'une fonction

 foo(); 

Ici, this se référera à nouveau à l'objet global .

ES5 Remarque: En mode strict, l'affaire globale n'existe plus . this aura plutôt la valeur d' undefined dans ce cas.

Appel d'une méthode

 test.foo(); 

Dans cet exemple, this se référera au test .

Appeler un constructeur

 new foo(); 

Un appel de fonction qui est précédé par le new mot-clé agit comme un constructeur. À l'intérieur de la fonction, this se référera à un nouvel Object créé .

Paramètre explicite de this

 function foo(a, b, c) {} var bar = {}; foo.apply(bar, [1, 2, 3]); // array will expand to the below foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3 

Lorsque vous utilisez l' call ou apply méthodes de Function.prototype , la valeur de this valeur dans la fonction appelée est explicitement définie sur le premier argument de l'appel de fonction correspondant.

En conséquence, dans l'exemple ci-dessus, le cas de la méthode ne s'applique pas , et this intérieur de foo sera mis en bar .

Remarque: this ne peut pas être utilisé pour désigner l'objet à l'intérieur d'un Object littéral. Donc, var obj = {me: this} ne me fera pas référence à obj , car this ne relève que de l'un des cinq cas listés.

Pièges courants

Bien que la plupart de ces cas aient du sens, le premier doit être considéré comme une autre mauvaise conception de la langue car il n'a jamais d'utilisation pratique.

 Foo.method = function() { function test() { // this is set to the global object } test(); } 

Une idée fausse commune est que this de test réfère à Foo ; Alors qu'en fait, ce n'est pas le cas .

Afin d'accéder à Foo partir du test interne, il est nécessaire de créer une variable locale dans la method qui se réfère à Foo .

 Foo.method = function() { var that = this; function test() { // Use that instead of this here } test(); } 

C'est juste un nom de variable normal, mais il est couramment utilisé pour la référence à un externe. En combinaison avec des fermetures, il peut également être utilisé pour passer this valeurs autour.

Affectation des méthodes

Une autre chose qui ne fonctionne pas dans JavaScript est l'aliasing de la fonction, qui affecte une méthode à une variable.

 var test = someObject.methodTest; test(); 

En raison du premier cas, le test maintenant comme un appel de fonction simple; Par conséquent, this ne se rapportera plus à someObject .

Bien que la contraction tardive de this puisse sembler une mauvaise idée au début, en fait, c'est ce qui fait que les héritages prototypiques fonctionnent.

 function Foo() {} Foo.prototype.method = function() {}; function Bar() {} Bar.prototype = Foo.prototype; new Bar().method(); 

Lorsque la method est appelée sur une instance de Bar , this se référera maintenant à cette instance même.

Disclaimer: Shamelessy volé de mes propres ressources à http://bonsaiden.github.com/JavaScript-Garden/#function.this

La raison pour laquelle vous appelez f comme une function et non comme une method . Lorsqu'elle est appelée comme une fonction, this est définie sur la window lors de l'exécution de la cible

 // Method invocation. Invoking a member (go) of an object (a). Hence // inside "go" this === a a.go(); // Function invocation. Invoking a function directly and not as a member // of an object. Hence inside "f" this === window f(); // Function invocation. var example = a.go; example(); 

La portée de toutes les fonctions est la window .

Pour contourner cela, vous pouvez le faire:

 function A() {} A.prototype.go = function() { var self = this; console.log(self); //A { go=function()} var f = function() { console.log(self); //A { go=function()} }; f(); } 

Parce que la fonction f() n'est pas appelée sans référence d'objet. Essayer,

 f.apply(this);