Javascript:将自定义参数传递给回调函数

6
我有这个回调函数设置:
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,据我所知,它不支持向其回调函数发送自定义数据。正是在这种情况下我遇到了这个问题。任何在这种环境中克服这个问题的建议也很有帮助!

可能是此帖子和其他几篇文章的重复。 - Wayne
3个回答

16

谢谢!我曾多次对“闭包”感到困惑,现在通过一些实践经验,它变得更加清晰了! - rsmoorthy
闭包非常棒,特别是在JavaScript中函数是一等对象的情况下,很难没有闭包。想象一下将函数中引用的每个变量都作为参数传递-在这种情况下,无论是callbackurl还是所有关于参数是按值传递还是按引用传递的麻烦都会出现。 - Anurag
我认为值得注意的是,并不是闭包本身使其起作用,而更具体地说,这个闭包代码包括传递参数 - 这使得传递按值进行,在原始闭包中保留引用的位置,从而克服了原始问题。我认为这样解释更完整。 - matanster

3

您正在 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/


0

通用解决方案

回调函数创建助手

我创建了一个通用的回调函数创建助手,如在循环中创建闭包:常见错误所述,Anurag 指出了 在他的答案中

回调函数创建助手的参数

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

传递回调函数的参数

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

源代码

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接