2009-05-24 14 views
5

quando passo 'questo' ad una funzione anonima in questo modo:Come vengono trasmessi i dati alle funzioni anonime in JavaScript?

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

ottengo "this.onTimeout non è una funzione" -Errore. Immagino che "questo" non sia più disponibile al momento dell'esecuzione della funzione anonima? Così ho fatto questo:

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

È davvero così che dovresti fare le cose? Funziona un po ', ma sembra strano.

Poi abbiamo questo esempio:

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

}); 

This uscite:

2 
2 

Qualora non fosse uscita:

1 
2 

invece? Poi ho scoperto che mettere il $ GetJSON-dichiarazione in un'altra funzione rende tutto il lavoro:

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

Questo uscite: (. O viceversa)

1 
2 

cosa sta succedendo qui? Qual è il modo giusto per passare variabili a una funzione anonima?

Ci scusiamo per il post confuso e lungo.

risposta

5

Quello che stai vivendo è il comportamento corretto - non è un buon comportamento, ma è parte del linguaggio. Il valore di "questo" viene reimpostato all'interno della definizione di funzione ogni. Esistono quattro modi per chiamare una funzione che ha diversi modi di impostare "questo".

  1. La normale funzione di chiamata
    myFunc(param1, param2);
    Questo modo di chiamare una funzione reimposterà sempre "questo" all'oggetto globale. Questo è ciò che sta accadendo nel tuo caso.
  2. Chiamarlo come un metodo
    myObj.myFunc(param1, param2);
    Questo non sorprende imposta "questo" a qualsiasi oggetto viene chiamato il metodo. Qui "questo" == "mioObj".
  3. Applica il metodo di chiamata
    myFunc.apply(myObj, [param1, param2])
    Questo è interessante: qui "questo" è impostato sull'oggetto che si passa come primo parametro al metodo apply - è come chiamare un metodo su un oggetto che non ha quel metodo (attenzione che la funzione è scritta per essere chiamata in questo modo).Tutte le funzioni di default hanno il metodo apply.
  4. Come costruttore (con "nuovo")
    myNewObj = new MyConstructor(param1, param2);
    Quando si chiama una funzione in questo modo, "questo" viene inizializzato su un nuovo oggetto che eredita metodi e proprietà dalla proprietà prototipo della propria funzione. In questo caso, il nuovo oggetto erediterà da MyConstructor.prototype. Inoltre, se non si restituisce un valore esplicitamente, "questo" verrà restituito.

La soluzione si è utilizzato è la soluzione consigliata - assegnare il valore al di fuori di "questo" per un'altra variabile che saranno ancora visibili all'interno vostra funzione. L'unica cosa che cambierei è chiamare la variabile "that" come dice Török Gábor - è una specie di standard de facto e potrebbe rendere il tuo codice più facile da leggere per altri programmatori.

+0

Cool! Molte grazie! Hm, immagino di essere abbastanza comodo con il funzionamento di js. È un po 'come LUA. È solo che continuo a pensare "Java" e questo non vale davvero – 0scar

3

Sei confuso circa le chiusure.

Per il primo problema, sì, hai ragione, questo è il modo in cui può essere fatto. L'unica differenza è che esiste una convenzione per denominare la variabile that che contiene this.

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

C'è già una bella discussione su StackOverflow. Controllare le risposte alla domanda How does a javascript closure work?.

Il tuo secondo problema è un duplicato esatto di Javascript closure inside loops - simple practical example.

+0

Grazie D00D! Quello era:) – 0scar

0

si avrà lo stesso problema se all'interno del nuovo metodo: nuovoRichiedi di utilizzare una dichiarazione "for" o "while". Un'altra soluzione potrebbe essere la creazione di una chiusura:

così:

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