简体   繁体   English

根据它们的构造方式,回调也可以定义为闭包吗?

[英]Based on how they are constructed, can callbacks also be defined as closures?

In JavaScript, I know that a closure is can be defined as a nested function that has access to its containing function's variables. 在JavaScript中,我知道闭包可以定义为嵌套函数,可以访问其包含函数的变量。 For example: 例如:

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

Now, the following code is wiring up a callback for the onreadystatechange property of the request object; 现在,以下代码为请求对象的onreadystatechange属性连接回调; however, I was wondering if, by definition, this is also considered to be a closure : 但是, 我想知道,根据定义,这是否也被视为封闭

/* 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...
    }
}

I realize that the handleResponse function could also just be written as an anonymous function in the context of submitHandler , but I find that more complex Ajax code can be more readable and easily maintained if callbacks are defined outside the scope of the function calling back to them. 我意识到handleResponse函数也可以在submitHandler的上下文中作为匿名函数submitHandler ,但我发现如果在函数调用范围之外定义回调,那么更复杂的Ajax代码可以更易读并且更容易维护。 Again, this is a contrived example that I'm using in hopes of simply demonstrating the point of my question. 同样,这是一个人为的例子,我希望能够简单地说明我的问题。

Yes, you are correct in assuming that it is a closure by definition. 是的,根据定义,假设它是一个闭包是正确的。

It sounds like you know your stuff but here is a good, extensive article on javascript closures . 这听起来像你知道你的东西,但这是一篇关于javascript闭包的好文章

I wholeheartedly agree that too many inline closure functions don't enhance readability. 我完全同意太多的内联闭包函数不会增强可读性。 On the other hand I strongly dislike the var self = this style of writing closures, to which this is just a variant, as it's still too verbose in its declaration, and you introduce your own new 'keyword' whether that is this or self . 另一方面,我非常不喜欢var self = this写闭包的风格, this只是一个变体,因为它在声明中仍然过于冗长,并且你引入了自己的新“关键字”,无论是this还是self

What you want is to curry/bind the method. 你想要的是咖喱/绑定方法。

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

The methods are taken from the Prototype library. 这些方法取自Prototype库。 I use these even in projects that don't use the Prototype library as they are very useful! 我甚至在不使用Prototype库的项目中使用它们,因为它们非常有用!

In your case this means instead of writing: 在你的情况下,这意味着而不是写:

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

you can now write: 你现在可以写:

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

However if you want to transfer the meaning of the this keyword you could do this 但是,如果要转移this关键字的含义,可以执行此操作

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

handleResponse , when called, will have the same this context as the submitHandler . handleResponse ,调用时,都会有相同的this方面的submitHandler

Your first example is not a closure. 你的第一个例子不是闭包。 It would have been had you returned innerFunction but you are executing the innerFunction and returning the result. 如果您返回了innerFunction,但是您正在执行innerFunction并返回结果。

The second example works and is using a closure. 第二个例子可以使用闭包。 One caveat with this specific technique is that you can end up with quite a severe memory leak in some browser implementations (IE certainly and may be others). 使用这种特定技术的一个警告是,在某些浏览器实现中可能会导致非常严重的内存泄漏(IE当然也可能是其他浏览器)。 You will have created a circular reference between the xhr held in oRequest, the onreadystatechange referencing a function and that functions scope being the scope where the xhr is held. 您将在oRequest中保存的xhr,引用函数的onreadystatechange和作为xhr所在范围的函数作用域之间创建循环引用。 Not only will the xhr remain in memory so will the response which if large (and especially if XML) can gobble memory quickly. xhr不仅会保留在内存中,因此响应如果很大(特别是如果是XML)可以快速吞噬内存。

Set the onreadystatechange property to an empty global level function during the handling for the response. 在处理响应期间,将onreadystatechange属性设置为空的全局级别函数。 This will break the circle. 这将打破这个圈子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM