How can you create a closure in a loop that which captures variables and takes parameters in Javascript?
我正在尝试为vis.js网络创建一个click事件处理程序,如下例所示:
1
2
3
4
5 network.on("click", function (params) {
params.event ="[original event]";
document.getElementById('eventSpan').innerHTML = 'Click event:' + JSON.stringify(params, null, 4);
console.log('click event, getNodeAt returns: ' + this.getNodeAt(params.pointer.DOM));
});`
但是我试图在循环中这样做,并希望匿名事件处理函数能够在循环中使用局部变量(在连续迭代中更改它们之前)。
例如:
1 2 3 4 5 6 7 | for (data in data_list) { var network = new vis.Network(data['container'], data['data'], data['options']); network.on("click", function(params) { console.log(data) // On event, data always equal to last element in data_list. I want it to save the data from the iteration this function was created in console.log(params) // I also need to access 'params' } } |
我知道这应该用一个闭包来完成,但是我找不到任何关于如何执行此操作的示例,同时还保持对传入的'params'的访问。如何创建一个可以接受'params'参数的闭包但是 还保存'数据'的状态?
我通常外化函数,传递我想要保留的数据并返回一个接受处理程序参数的函数:
1 2 3 4 5 6 7 8 9 10 11 | function getOnClickHandler(data) { return function(params) { console.log(data); console.log(params); } } for (data in data_list) { var network = new vis.Network(data['container'], data['data'], data['options']); network.on("click", getOnClickHandler(data)); } |
啊,这是一个循环的回调问题。
对于这种情况发生的原因的解释是,在收到单击事件之前,您的代码将完整地执行。它意味着它通过创建新网络,定义新的onClick处理程序,然后将它们添加到网络来循环。虽然这些处理程序中的每一个都是独立的,但它们都捕获相同的数据变量,这将在循环结束时最终引用最后一个数据元素。
1 2 3 4 5 | var arr = [1, 2, 3, 4, 5] for (i in arr) { setTimeout(function () { console.log(i) }, 1000); } // prints 4, 4, 4, 4, 4 |
有两种方法可以解决此问题。第一种方法是利用ES 6的
1 2 3 4 5 | var arr = [1, 2, 3, 4, 5] for (let i in arr) { // NOTE THE USE OF let HERE. setTimeout(function () { console.log(i) }, 1000); } // prints 0, 1, 2, 3, 4 |
第二种方法是将
1 2 3 4 5 6 7 8 9 | function handlerWrapper(i) { return function() { console.log(i) }; } var arr = [1, 2, 3, 4, 5] for (i in arr) { setTimeout(handlerWrapper(i), 1000); } // prints 0, 1, 2, 3, 4 |
通过这种安排,您的参数应该适用于您的回调函数:
1 2 3 | function handlerWrapper(data) { return function(params) { console.log(data, params) }; } |
1 2 3 4 5 6 7 | for (data in data_list) { var network = new vis.Network(data['container'], data['data'], data['options']); network.on("click", (params) => { console.log(data) // On event, data always equal to last element in data_list. I want it to save the data from the iteration this function was created in console.log(params) // I also need to access 'params' } } |
如果您需要进一步澄清,请与我们联系。