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 代码可以更易读和更容易维护。同样,这是一个人为的例子,我正在使用它来简单地展示我的问题的重点。

4

3 回答 3

3

是的,您假设它是定义上的闭包是正确的。

听起来你知道你的东西,但这里有一篇关于 javascript 闭包的好文章

于 2009-01-19T13:19:59.100 回答
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库。即使在不使用原型库的项目中,我也会使用它们,因为它们非常有用!

在你的情况下,这意味着而不是写:

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

于 2009-01-19T13:25:14.843 回答
1

您的第一个示例不是闭包。如果您返回了 innerFunction 但您正在执行 innerFunction 并返回结果,那将会是这样。

第二个示例有效并且正在使用闭包。这种特定技术的一个警告是,您最终可能会在某些浏览器实现中出现相当严重的内存泄漏(IE 当然也可能是其他浏览器)。您将在 oRequest 中保存的 xhr、引用函数的 onreadystatechange 和作为保存 xhr 的范围的函数范围之间创建循环引用。不仅 xhr 将保留在内存中,如果响应很大(尤其是 XML 时),响应也会迅速吞噬内存。

在处理响应期间,将 onreadystatechange 属性设置为空的全局级别函数。这将打破循环。

于 2009-01-19T13:37:12.620 回答