var函数=[];//让我们创建3个函数对于(变量i=0;i<3;i++){//并将其存储在funcs中funcs[i]=函数(){//每个都应该记录其值。console.log(“我的值:”,i);};}对于(变量j=0;j<3;j++){//现在让我们逐一查看函数[j]();}
它输出以下内容:
我的价值:3我的价值:3我的价值:3
而我希望它输出:
我的值:0我的价值:1我的价值:2
当使用事件侦听器导致函数运行延迟时,也会出现同样的问题:
var buttons=document.getElementsByTagName(“button”);//让我们创建3个函数for(var i=0;i<buttons.length;i++){//作为事件侦听器buttons[i].addEventListener(“单击”,函数(){//每个都应该记录其值。console.log(“我的值:”,i);});}<按钮>0</按钮><br/><button>1</button><br/><按钮>2</按钮>
…或异步代码,例如使用Promises:
//一些异步等待函数const wait=(ms)=>new Promise((解析,拒绝)=>setTimeout(解析,ms));对于(变量i=0;i<3;i++){//一旦每个承诺得到解决,就记录“i”。等待(i*100)。然后(()=>console.log(i));}
在for in和for of循环中也很明显:
常量arr=[1,2,3];常量fns=[];用于(arr中的变量i){fns.push(()=>console.log(“index:”,i));}对于(arr的var v){fns.push(()=>console.log(“值:”,v));}for(arr常量){var obj={number:n};//或新的MyLibObject({…})fns.push(()=>console.log(“n:”,n,“|”,“obj:”,JSON.stringify(obj)));}for(fns的var f){f();}
这个基本问题的解决方案是什么?
您可以为数据列表(如查询js(*))使用声明性模块。在这些情况下,我个人认为声明性方法不太令人惊讶
var funcs = Query.range(0,3).each(function(i){
return function() {
console.log("My value: " + i);
};
});
然后,您可以使用第二个循环并获得预期的结果,也可以这样做
funcs.iterate(function(f){ f(); });
(*)我是query js的作者,因此倾向于使用它,所以不要将我的话作为仅针对声明性方法的所述库的建议:)
您可以为数据列表(如查询js(*))使用声明性模块。在这些情况下,我个人认为声明性方法不太令人惊讶
var funcs = Query.range(0,3).each(function(i){
return function() {
console.log("My value: " + i);
};
});
然后,您可以使用第二个循环并获得预期的结果,也可以这样做
funcs.iterate(function(f){ f(); });
(*)我是query js的作者,因此倾向于使用它,所以不要将我的话作为仅针对声明性方法的所述库的建议:)
你的代码不起作用,因为它的作用是:
Create variable `funcs` and assign it an empty array;
Loop from 0 up until it is less than 3 and assign it to variable `i`;
Push to variable `funcs` next function:
// Only push (save), but don't execute
**Write to console current value of variable `i`;**
// First loop has ended, i = 3;
Loop from 0 up until it is less than 3 and assign it to variable `j`;
Call `j`-th function from variable `funcs`:
**Write to console current value of variable `i`;**
// Ask yourself NOW! What is the value of i?
现在问题是,调用函数时变量i的值是多少?因为第一个循环是在i<3的条件下创建的,所以当条件为false时,它会立即停止,所以它是i=3。
您需要理解,当您的函数被创建时,它们的代码都不会被执行,只会被保存以备以后使用。因此,当稍后调用它们时,解释器会执行它们并问:“i的当前值是多少?”
因此,您的目标是首先将i的值保存到函数,然后才将函数保存到funcs。例如,可以这样做:
var funcs = [];
for (var i = 0; i < 3; i++) { // let's create 3 functions
funcs[i] = function(x) { // and store them in funcs
console.log("My value: " + x); // each should log its value.
}.bind(null, i);
}
for (var j = 0; j < 3; j++) {
funcs[j](); // and now let's run each one to see
}
这样,每个函数都有自己的变量x,我们在每次迭代中将这个x设置为i的值。
这只是解决这个问题的多种方法之一。
您需要了解的是javascript中变量的范围是基于函数的。这与c#有一个重要的区别,因为c#有块作用域,只需将变量复制到for中的一个即可。
将其包装在一个函数中,该函数会像apphacker的答案那样计算返回函数的值,这会起到作用,因为变量现在具有函数作用域。
还有一个let关键字而不是var,这将允许使用块范围规则。在这种情况下,在for中定义一个变量就可以了。也就是说,由于兼容性,let关键字不是一个实用的解决方案。
var funcs={};对于(变量i=0;i<3;i++){设索引=i//添加此funcs[i]=函数(){console.log(“我的值:”+索引)//更改副本};}对于(变量j=0;j<3;j++){函数[j]();}