【问题标题】:Javascript: Passing custom arguments to a callback functionJavascript:将自定义参数传递给回调函数
【发布时间】:2011-07-05 21:18:35
【问题描述】:

我有这个回调函数设置:

var contextMenu = [];
var context = [ { "name": "name1", "url": "url1" }, {"name": name2", "url: "url2" } ];
for(var i=0; i < context.length; i++) {
    var c = context[i];
    var arr = {};
    arr[c.name] = function() { callback(c.url); }
    contextMenu.push( arr );
}
function callback(url) {
   alert(url);
}

问题在于传递给回调的 url 值始终是上下文变量中的最后一个值——在本例中为“url2”。我期望将特定的值传递给回调的每个“实例”,但由于回调似乎记住了相同的值,因此上次引用它。

我有点卡住了。任何帮助将不胜感激。

PS:我正在使用jQuery ContextMenu,据我了解,它不支持将自定义数据发送到其回调函数。正是在这种情况下,我遇到了这个问题。在这种环境下要克服的任何建议也很有帮助!

【问题讨论】:

  • this post 和其他几十个的可能重复

标签: javascript loops callback closures


【解决方案1】:

使用额外的闭包。

arr[c.name] = (function(url) { 
    return function() { callback(url); }
})(c.url);

请参阅Creating closures in loops: A common mistake 和大多数其他questions 关于此主题,现在您的问题也已添加到此池中。

【讨论】:

  • 谢谢!我多次被“关闭”迷惑,现在有了一些实践经验,它变得更加清晰!
  • 闭包非常棒,尤其是因为函数是 JavaScript 中的一等对象,没有闭包就很难做到。想象一下,将函数中引用的每个变量都作为参数传递——在这种情况下,callbackurl 以及参数是通过值传递还是通过引用传递的所有令人头疼的问题。
  • 我认为值得注意的是,并不是闭包本身使它工作,而是更具体地说,这个闭包代码包括传递一个参数——这使得按值传递代替引用保留在原始闭包中,从而克服了原始问题。我认为这使解释更加完整。
【解决方案2】:

你在 for 循环中创建了一系列闭包函数

arr[c.name] = function() { callback(c.url); }

并且它们都共享相同的范围,因此相同的 c 对象将在循环结束后指向数组中的最后一个元素。

要解决此问题,请尝试这样做:

arr[c.name] = function(url) {
    return function() { callback(url); };
}(c.url);

在此处阅读有关关闭的更多信息:http://jibbering.com/faq/notes/closures/

【讨论】:

    【解决方案3】:

    一般解决方案

    回调创建者助手

    我沿着Anurag 指出的in his answerCreating closures in loops: A common mistake 创建了一个通用回调创建器。

    回调创建者参数

    • 函数的第一个参数是回调。
    • 其他所有参数都将作为参数传递给此回调。

    传递的回调参数

    • 参数的第一部分来自您传递给回调创建器助手的参数(在我之前描述的第一个参数之后)。
    • 第二部分来自调用者将直接传递给回调的参数。

    源代码

    //Creates an anonymus function that will call the first parameter of
    //this callbackCreator function (the passed callback)
    //whose arguments will be this callbackCreator function's remaining parameters
    //followed by the arguments passed to the anonymus function
    //(the returned callback).
    function callbackCreator() {
        var functionToCall = arguments[0];
        var argumentsOfFunctionToCall = Array.prototype.slice.apply(arguments, [1]);
        return function () {
            var argumentsOfCallback = Array.prototype.slice.apply(arguments, [0]);
            functionToCall.apply(this, argumentsOfFunctionToCall.concat(argumentsOfCallback));
        }
    }
    

    示例用法

    这是一个自定义的 AJAX 配置对象,它的成功回调使用我的回调创建者助手。使用响应文本,回调根据操作发生的行更新DataTables 表中行的第一个单元格,并打印一条消息。

    {
        url: 'example.com/data/' + elementId + '/generate-id',
        method: 'POST',
        successHandler: callbackCreator(function (row, message, response) {//Callback parameters: Values we want to pass followed with the arguments passed through successHandler.
                table.cell(row, 0).data(JSON.parse(response).text);
                console.log(message);
            },
            $(this).parents('tr'),//Row value we want to pass for the callback.
            actionName + ' was successful'//Message value we want to pass for the callback.
        )
    }
    

    或者在你的情况下:

    arr[c.name] = callbackCreator(function(url) {
            callback(url);
        },
        c.url
    );
    

    【讨论】:

      猜你喜欢
      • 2011-03-28
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-07
      相关资源
      最近更新 更多