在JavaScript中将状态传递给回调函数是否正确使用闭包?

在JavaScript中将状态传递给回调函数是否正确使用闭包?,javascript,closures,Javascript,Closures,假设您希望在JavaScript中发出异步请求,但希望向回调方法传递一些状态。以下是JavaScript中闭包的适当用法吗 function getSomethingAsync(someState, callback) { var req = abc.createRequestObject(someParams); req.invoke(makeCallback(someState, callback)); } function makeCallback(someState,

假设您希望在JavaScript中发出异步请求,但希望向回调方法传递一些状态。以下是JavaScript中闭包的适当用法吗

function getSomethingAsync(someState, callback) {
    var req = abc.createRequestObject(someParams);
    req.invoke(makeCallback(someState, callback));
}

function makeCallback(someState, callback) {
    return function getSomethingCallback(data) {
        var result = processDataUsingState(data, someState);
        callback(result); // alternately/optionally pass someState along to result
    }
}
如果没有,有更好或更惯用的方法吗?

使用匿名函数更好(更好):

function getSomethingAsync (someState, callback) {
    req.invoke (function (data) {
       var result = processDataUsingState (data, someState);
       callback (result);
    });
}

我看不出这有什么直接的问题——闭包之所以强大有很多原因,其中之一就是不再需要使用全局变量来维护状态

也就是说,关于闭包,您需要注意的唯一一件事是通常发生在IE中的内存泄漏,但这些通常是IIRC,与DOM元素和附加到其上的事件处理程序有关


继续

更惯用的方法是使用,这样就不需要复制代码来创建闭包。我将使用一个简单的示例(没有自定义代码)来解释

/**
 * Retrieves the content of a url asyunchronously
 * The callback will be called with one parameter: the html retrieved
 */
function getUrl(url, callback) {
    $.ajax({url: url, success: function(data) {
        callback(data);
    }})    
}

// Now lets' call getUrl twice, specifying the same 
// callback but a different id will be passed to each
function updateHtml(id, html) {
    $('#' + id).html(html);
}


// By calling bind on the callback, updateHTML will be called with 
// the parameters you passed to it, plus the parameters that are used
// when the callback is actually called (inside )
// The first parameter is the context (this) to use, since we don't care,
// I'm passing in window since it's the default context
getUrl('/get/something.html', updateHTML.bind(window, 'node1'));
// results in updateHTML('node1', 'response HTML here') being called
getUrl('/get/something-else.html', updateHTML.bind(window, 'node2'));
// results in updateHTML('node2', 'response HTML here') being called
Function.bind
是新功能,因此如果需要向后支持,请查看


最后,我知道这个问题没有标记为jQuery。这是在不处理跨浏览器问题的情况下显示异步函数的最快方法

您还可以使用call()/apply()操作函数中“This”的值

例如,指定异步方法的另一个参数是在回调中用作“this”的对象。这就是jQuery在事件回调中将dom节点设置为“This”的方式

function getSomethingAsync(callback, scope) {
    var req = abc.createRequestObject(someParams);
    req.invoke(function(rsp) {
      callback.apply(scope, [rsp]);
    });
}

// usage:
getSomethingAsync(function() {console.log(this.someState)}, {someState:'value'});

哈维尔…为什么这样更好?否决这个的人…为什么这不是一个好答案?只是为了避免繁文缛节:一个函数调用和额外的名称只是为了在您可以当场创建闭包时创建闭包。记住,给一个函数命名就是简单地把它赋给一个变量;如果他的makeCallback()函数没有在其他任何地方使用,那么您的简化肯定是有用的,如果是,那么您就必须复制代码。有时,将内容分解为命名函数有助于可读性。命名函数使签出堆栈TraceGod点时易于阅读。下面是对IE泄漏问题的讨论:很好!谢谢你指出这一点。当然,这在我2008年第一次写这个问题时并不存在。考虑到它只是IE9,我想在使用它之前我会等一段时间……你不应该等。MDN的链接包含了使其在任何浏览器中都能正常工作所需的代码。是的,我看到了解决方法,但它有太多的警告,所以我将有关它的阅读留到下一次:-)