2009-04-02 9 views
25

Le comportement de "this" lorsque la fonction bar est appelée me déroute. Voir le code ci-dessous. Est-il possible de faire en sorte que "this" soit une ancienne instance d'objet js lorsque bar est appelé à partir d'un gestionnaire de clic, au lieu d'être l'élément html?jQuery/JavaScript "this" confusion du pointeur

// a class with a method 

function foo() { 

    this.bar(); // when called here, "this" is the foo instance 

    var barf = this.bar; 
    barf(); // when called here, "this" is the global object 

    // when called from a click, "this" is the html element 
    $("#thing").after($("<div>click me</div>").click(barf)); 
} 

foo.prototype.bar = function() { 
    alert(this); 
} 
+0

Veuillez expliquer le '' ceci "est l'instance de foo'. Le fichier jsfiddle suivant (http://jsfiddle.net/yY6fp/1/) montre que 'this' dans' this.bar() 'est évalué à l'objet' window' (global). –

Répondre

33

Bienvenue dans le monde de javascript! : D

Vous avez erré dans le domaine de la portée et de la fermeture de javascript.

Pour la réponse courte:

this.bar() 

est exécuté sous le champ d'application de foo, (comme ce fait référence à foo)

var barf = this.bar; 
barf(); 

est exécuté sous la portée mondiale.

this.bar signifie essentiellement:

exécuter la fonction pointée par this.bar, sous le champ d'application de cette (foo). Lorsque vous avez copié this.bar sur barf et exécuté barf. Javascript compris comme, exécutez la fonction pointée par barf, et puisqu'il n'y a pas ce, il fonctionne juste dans la portée globale.

Pour corriger cela, vous pouvez changer

barf(); 

à quelque chose comme ceci:

barf.apply(this); 

Cela dit Javascript pour lier la portée de cette à barf avant de l'exécuter.

Pour les événements jquery, vous devez utiliser une fonction anonyme ou étendre la fonction de liaison dans prototype pour prendre en charge la portée.

Pour plus d'informations:

+2

Je ne suis pas sûr à 100% sur la terminologie moi-même, mais je pense que cette réponse (et les ressources liées à) confondent 'scope' avec 'context d'exécution'. L'objet pointé par 'this' est le * contexte d'exécution *, et est entièrement indépendant de * scope * (que les fermetures ont à voir avec). La portée est déterminée au moment de la création d'une fonction et détermine les variables que la fonction peut voir; Le contexte d'exécution est déterminé chaque fois que la fonction est appelée, et détermine à quoi cela se réfère. Remplacer «scope» par «contexte d'exécution» partout ici et alors seulement sera-t-il correct - je pense! –

1

C'est parce que ce est toujours l'instance que la fonction est attaché. Dans le cas d'un EventHandler, c'est la classe qui a déclenché l'événement.

Vous pouvez aider votre auto avec une fonction anonyme comme ceci:

function foo() { 
    var obj = this; 
    $("#thing").after($("<div>click me</div>").click(function(){obj.bar();})); 
} 

foo.prototype.bar = function() { 
    alert(this); 
} 
2

Vous peut utiliser Function.apply sur la fonction pour définir ce this doit se référer à:

$("#thing").after($("<div>click me</div>").click(function() { 
    barf.apply(document); // now this refers to the document 
}); 
+1

Outre le fait qu'il manque un crochet fermé à votre code - la fonction * apply * exécute instantanément la fonction * barf * au lieu de renvoyer un pointeur de fonction. – Martin

+0

Merci, j'ai maintenant corrigé le post :) – moff

5

Il y a une bonne explication sur le mot-clé this JavaScript disponible à QuirksMode.

0
this.bar(); // when called here, "this" is the foo instance 

ce commentaire est erroné lorsque foo est utilisé comme une fonction normale, et non comme un constructeur. ici:

foo();//this stands for window