2009-01-19 45 views
4

在JavaScript中,我知道閉包可以被定義爲一個嵌套函數,它可以訪問它的包含函數的變量。例如:根據它們的構造方式,回調函數也可以定義爲閉包?

function outerFunction(x, y) { 
    function innerFunction() { 
     return x + y + 10; 
    } 
    return innerFunction; 
} 

現在,下面的代碼是連接最多爲請求對象的屬性onreadystatechange回調;然而,我在想,如果,顧名思義,這也被認爲是一個封閉

/* This is a contrived example, I know. 
* Bear with me - it demonstrates the point I'm trying to convey. */ 

function submitHandler() { 

    var oRequest = createRequest(); // assume I'm getting an instance of the xhr 
    var sUsername = 'Tom';   // assume this is needed for work in the handler 
    var This = this; 
    oRequest.onreadystatechange = function() { 
     This.handleResponse(oRequest, sUsername) 
    } 

} 

function handleResponse(oResponse, sUsername) { 
    if(oResponse.readyState === 4 && oResponse.status === 200) { 
     // do work with the username 
    } else { 
     // we're not done yet... 
    } 
} 

我意識到handleResponse功能也只是被寫成的submitHandler背景下的匿名函數,但我發現如果回調函數在函數調用範圍之外定義,那麼更復雜的Ajax代碼可以更易讀並且易於維護。再次,這是一個人爲的例子,我只是用來展示我的問題。

回答

3

我完全同意太多的內聯閉包函數不會增強可讀性。另一方面,我強烈不喜歡var self = this寫作封閉風格,其中this只是一個變體,因爲它在聲明中仍然過於冗長,並且引入了您自己的新「關鍵字」,無論是this還是self

你想要的是咖喱/綁定方法。

function $A(o) 
{ 
    var a = []; 
    for (var i = 0; i < o.length; ++i) 
     a.push(o[i]); 
    return a; 
} 

Function.prototype.bind = function() 
{ 
    var _method = this; 
    var a = $A(arguments) 
    var o = a.shift(); 

    return function() 
    { 
     return _method.apply(o, a.concat($A(arguments))); 
    } 
} 

Function.prototype.curry = function() 
{ 
    var _method = this; 
    var a = $A(arguments); 

    return function() 
    { 
     return _method.apply(null, a.concat($A(arguments))); 
    } 
} 

該方法取自Prototype庫。我甚至在不使用Prototype庫的項目中使用它們,因爲它們非常有用!

在你的情況,這意味着,而不需要編寫:

var This = this; 
oRequest.onreadystatechange = function() { 
    This.handleResponse(oRequest, sUsername) 
} 

你現在可以這樣寫:

oRequest.onreadystatechange = this.handleResponse.curry(oRequest,sUsername); 

但是,如果你想轉讓,你能做到這一點

this關鍵字的含義
oRequest.onreadystatechange = this.handleResponse.bind(this,oRequest,sUsername); 

handleResponse當被調用時,將具有相同的this上下文爲submitHandler

1

你的第一個例子不是閉包。它會讓你返回innerFunction,但你正在執行innerFunction並返回結果。

第二個示例工作並正在使用閉包。使用這種特定技術的一個警告是,你可能會在某些瀏覽器實現中發生相當嚴重的內存泄漏(IE當然也可能是其他)。您將在oRequest中保留的xhr,引用函數的onreadystatechange和作爲xhr被保留的範圍的函數作用域之間創建一個循環引用。 xhr不僅會保留在內存中,所以如果很大(特別是如果XML)的響應可能會迅速吞噬內存。

在處理響應期間,將onreadystatechange屬性設置爲空的全局級別函數。這將打破這個圈子。

+0

+1注意到第一個不是閉包。 – 2009-01-19 13:43:42

相關問題