2009-05-24 89 views
5

當我通過「這個」到一個匿名函數,像這樣:數據如何傳遞給JavaScript中的匿名函數?

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

我得到一個「this.onTimeout不是一個函數」誤差。我猜在匿名函數執行時'this'不再可用了嗎?所以我一直這樣做:

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

這是真的如何你應該做的事情?它有點不錯,但感覺很奇怪。

然後,我們有這樣的例子:

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

}); 

此輸出:

2 
2 

難道不應該輸出:

1 
2 

呢?後來我發現,把$ .getJSON語句中的另一個功能使得它所有的工作:

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

此輸出:(或者反過來)

1 
2 

這裏發生了什麼?將變量傳遞給匿名函數的正確方法是什麼?

對不起,這個令人困惑和冗長的帖子。

回答

5

你正在經歷的是正確的行爲 - 這不是一個好的行爲,但它是語言的一部分。 「this」的值在內每函數定義被重置。有四種方法可以調用具有不同方式設置「this」的函數。

  1. 常規函數調用
    myFunc(param1, param2);
    這種調用函數的方式總是會將「this」重置爲全局對象。這就是你的情況。
  2. 將其稱爲方法
    myObj.myFunc(param1, param2);
    這毫不意外地將「this」設置爲該方法被調用的任何對象。在這裏,「this」==「myObj」。
  3. 應用方法調用
    myFunc.apply(myObj, [param1, param2])
    這是一個很有意思的方法 - 在這裏,「this」被設置爲您作爲apply方法的第一個參數傳遞的對象 - 就像在沒有該方法的對象上調用方法一樣該函數被寫入以這種方式被調用)。所有功能默認都有apply方法。
  4. 作爲構造函數(帶有「new」)
    myNewObj = new MyConstructor(param1, param2);
    當您以這種方式調用函數時,「this」被初始化爲一個新的對象,該對象從函數的prototype屬性繼承方法和屬性。在這種情況下,新對象將從MyConstructor.prototype繼承。另外,如果你沒有明確地返回一個值,那麼將返回「this」。

您使用的解決方案是推薦的解決方案 - 將「this」的外部值分配給另一個變量,該變量在您的函數中仍然可見。我唯一要改變的就是像TörökGábor所說的那樣調用變量「that」 - 這是事實上的標準,可能會讓你的代碼更容易被其他程序員閱讀。

+0

很酷!非常感謝!嗯,我想我對js的工作起到了很大的舒適作用。這有點像LUA。這只是我一直在想「Java」,這並不適用。 – 0scar 2009-05-27 12:26:03

3

你對關閉感到困惑。

對於第一個問題,是的,你是對的,那是它可以完成的方式。唯一的區別是有一個約定來命名變量that,該變量包含this

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

在StackOverflow上已經有了一個很好的線程。檢查問題 How does a javascript closure work?的答案。

你的第二個問題是一個完全重複的Javascript closure inside loops - simple practical example

+0

感謝D00D!那就是:) – 0scar 2009-05-24 14:50:45

0

如果在新方法中:newRequest必須使用「for」或「while」語句,您將會遇到同樣的問題。 另一種解決方案可以創建一個封閉:

這樣的:

$.getJSON("answer.html",{},(function(me){return function(data){me.gotAnswer(count);}})(this)); 
相關問題