var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value:", i);
};
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
它输出以下内容:
我的值:3
我的值:3
我的值:3
而我希望它输出:
我的值:0
我的值:1
我的值:2
当运行函数的延迟是由使用事件侦听器引起的时,会出现同样的问题:
var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
// as event listeners
buttons[i].addEventListener("click", function() {
// each should log its value.
console.log("My value:", i);
});
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>
…或异步代码,例如使用 Promises:
// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));
for (var i = 0; i < 3; i++) {
// Log `i` as soon as each promise resolves.
wait(i * 100).then(() => console.log(i));
}
在和循环中也很明显:for in
for of
const arr = [1,2,3];
const fns = [];
for (var i in arr){
fns.push(() => console.log("index:", i));
}
for (var v of arr){
fns.push(() => console.log("value:", v));
}
for (const n of arr) {
var obj = { number: n }; // or new MyLibObject({ ... })
fns.push(() => console.log("n:", n, "|", "obj:", JSON.stringify(obj)));
}
for(var f of fns){
f();
}
这个基本问题的解决方案是什么?
网友回答:
尝试:
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = (function(index) {
return function() {
console.log("My value: " + index);
};
}(i));
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
编辑 (2014):
我个人认为@Aust最近关于使用的答案是现在做这种事情的最好方法。当您不需要或不想弄乱 ‘s 时,还有 lo-dash/下划线。.bind
_.partial
bind
thisArg
网友回答:
好吧,问题是 变量 ,在每个匿名函数中,绑定到函数外部的同一变量。i
let
ECMAScript 6 (ES6) 引入了 new 和 关键字,其作用域与基于变量的变量不同。例如,在具有基于 -的索引的循环中,循环的每次迭代都会有一个具有循环作用域的新变量,因此您的代码将按预期工作。有很多资源,但我推荐 2ality 的块范围帖子作为重要的信息来源。let
const
var
let
i
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
但是请注意,Edge 9 之前的 IE11-IE14 和 Edge 支持 3,但上述内容是错误的(它们不会每次都创建一个新函数,因此上面的所有函数都会像我们使用时一样记录 14)。边缘 <> 终于做对了。let
i
var
随着该函数的相对广泛的可用性(在 2015 年),值得注意的是,在那些主要涉及对值数组进行迭代的情况下,提供了一种干净、自然的方式来为每次迭代获得不同的闭包。也就是说,假设你有某种包含值(DOM 引用、对象等)的数组,并且出现设置特定于每个元素的回调的问题,你可以这样做:Array.prototype.forEach
.forEach()
var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
// ... code code code for this one element
someAsynchronousFunction(arrayElement, function() {
arrayElement.doSomething();
});
});
这个想法是,与循环一起使用的回调函数的每次调用都将是它自己的闭包。传递给该处理程序的参数是特定于迭代的特定步骤的数组元素。如果在异步回调中使用,则不会与在迭代的其他步骤中建立的任何其他回调发生冲突。.forEach
如果你碰巧在jQuery工作,这个函数会给你一个类似的功能。$.each()
您要做的是将每个函数中的变量绑定到函数外部的单独不变值:
var funcs = [];
function createfunc(i) {
return function() {
console.log("My value: " + i);
};
}
for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
由于 JavaScript 中没有块作用域 – 只有函数作用域 – 通过将函数创建包装在新函数中,您可以确保“i”的值保持您的预期。
网友回答:
另一种尚未提及的方法是使用Function.prototype.bind
var funcs = {};
for (var i = 0; i < 3; i++) {
funcs[i] = function(x) {
console.log('My value: ' + x);
}.bind(this, i);
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
更新
正如 @squint 和 @mekdev 所指出的,通过先在循环外部创建函数,然后在循环内绑定结果,可以获得更好的性能。
function log(x) {
console.log('My value: ' + x);
}
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = log.bind(this, i);
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
模板简介:该模板名称为【在每个匿名函数中,绑定到函数外部的同一变量】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【JavaScript】栏目查找您需要的精美模板。