2009-05-24 6 views
5

Quand je passe « ce » à une fonction anonyme comme ceci:Comment les données sont-elles transmises aux fonctions anonymes en JavaScript?

MyClass.prototype.trigger = function(){ 
    window.setTimeout(function(){this.onTimeout();},1000); 
} 

je reçois un « this.onTimeout est pas une fonction » -erreur. Je suppose que 'ceci' n'est plus disponible au moment où la fonction anonyme est en cours d'exécution? Donc, je fais ceci:

MyClass.prototype.trigger = function(){ 
    var me = this 
    window.setTimeout(function(){me.onTimeout();},1000); 
} 

Est-ce vraiment la façon dont vous êtes censé faire des choses? Ca marche un peu, mais ça fait bizarre.

Ensuite, nous avons cet exemple:

$(function(){ 
    function MyClass(){ 
     this.queue = new Array(); 
    } 
    MyClass.prototype.gotAnswer = function(count){ 
     $('body').append("count:"+count+"<br/>"); 
    } 
    MyClass.prototype.loadAll = function(){ 
     var count = 0; 
     var item; 
     while(item = this.queue.pop()){ 
      count++; 
      var me = this; 
      $.getJSON("answer.html",{},function(data){me.gotAnswer(count);}); 
     } 
    } 

    var o = new MyClass(); 
    o.queue.push(1); 
    o.queue.push(2); 
    o.loadAll(); 

}); 

Ce sorties:

2 
2 

ne devrait-elle sortie:

1 
2 

à la place? Ensuite, j'ai découvert que mettre la déclaration .getJSON $ dans une autre fonction fait tout le travail:

MyClass.prototype.loadAll = function(){ 
    var count = 0; 
    var item; 
    while(item = this.queue.pop()){ 
     count++; 
     this.newRequest(count); 
    } 
} 
MyClass.prototype.newRequest = function(count){ 
    var me = this; 
    $.getJSON("answer.html",null,function(data){ me.gotAnswer(count); }); 
} 

Cette sortie: (. Ou l'inverse)

1 
2 

Qu'est-ce qui se passe ici? Quelle est la bonne façon de passer des variables à une fonction anonnymous?

Désolé pour le poste confus et longue.

Répondre

5

Ce que vous rencontrez est le comportement correct - ce n'est pas un bon comportement, mais cela fait partie du langage. La valeur de "this" est réinitialisée dans chaque définition de fonction. Il y a quatre façons d'appeler une fonction qui ont différentes façons de définir "ceci". L'invocation de fonction normale

myFunc(param1, param2);
Cette façon d'appeler une fonction réinitialisera toujours "this" à l'objet global. C'est ce qui se passe dans votre cas.
  • L'appeler comme une méthode
    myObj.myFunc(param1, param2);
    Cela sans surprise met "this" à quel que soit l'objet auquel la méthode est appelée. Ici, "ceci" == "myObj".
  • Appliquer l'invocation de méthode
    myFunc.apply(myObj, [param1, param2])
    Ceci est intéressant - ici "ceci" est l'objet que vous passez comme premier paramètre de la méthode apply - c'est comme appeler une méthode sur un objet qui n'a pas cette méthode (attention que la fonction est écrite pour être appelée ainsi).Toutes les fonctions par défaut ont la méthode apply.
  • En tant que constructeur (avec "new")
    myNewObj = new MyConstructor(param1, param2);
    Lorsque vous appelez une fonction de cette façon, "this" est initialisé à un nouvel objet qui hérite des méthodes et des propriétés de la propriété prototype de votre fonction. Dans ce cas, le nouvel objet héritera de MyConstructor.prototype. De plus, si vous ne renvoyez pas une valeur explicitement, "this" sera retourné. La solution que vous avez utilisée est la solution recommandée. Affectez la valeur externe de "this" à une autre variable qui sera toujours visible dans votre fonction. La seule chose que je changerais, c'est d'appeler la variable "that" comme le dit Török Gábor - c'est en quelque sorte la norme de facto et cela pourrait rendre votre code plus facile à lire pour les autres programmeurs.

  • +0

    Cool! Merci beaucoup! Hm, je suppose que je suis en fait tout à fait à l'aise avec la façon dont js fonctionne. C'est un peu comme LUA. C'est juste que je continue à penser "Java" et ça ne s'applique pas vraiment .. – 0scar

    3

    Vous êtes confus au sujet des fermetures.

    Pour le premier problème, oui, vous avez raison, c'est comme ça qu'on peut le faire. La seule différence qu'il existe une convention pour nommer la variable that qui contient this.

    MyClass.prototype.trigger = function(){ 
        var that = this; 
        window.setTimeout(function(){that.onTimeout();},1000); 
    } 
    

    Il y a déjà un bon fil à ce sujet sur StackOverflow. Vérifiez les réponses à la question How does a javascript closure work?. Le deuxième problème est un doublon exact de Javascript closure inside loops - simple practical example.

    +0

    Merci D00D! C'était ça:) – 0scar

    0

    vous aurez le même problème si à l'intérieur de votre nouvelle méthode: newRequest vous devez utiliser une instruction "for" ou "while". Une autre solution pourrait être de créer une fermeture:

    comme ça:

    $.getJSON("answer.html",{},(function(me){return function(data){me.gotAnswer(count);}})(this)); 
    
    Questions connexes