这是我想要做的。 我有一个类似下面的数组
var my_array = ['1', '2', '3' ... ,'1000000000000000'];
我想要做的是为该数组的每个元素创建一堆HTML元素,并且因为该数组可以包含大量元素,所以我尝试执行以下操作,因此浏览器不会冻结。
for(var i in my_array)
{
if(my_array.hasOwnProperty(i))
{
setTimeout(function(){
do_something_with_data(my_array[i]);
});
}
}
虽然setTimeout中的my_array [i]没有应有的值,但会发生什么。
为了更准确,当我尝试console.log(my_array[i])
我得到的东西是这样的:
"getUnique" function (){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
getUnique是我添加到Array原型中的函数,如下所示:
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
};
有人可以帮我解决这个问题吗?
答案 0 :(得分:3)
在循环完成后执行setTimeout,i
是该点的最后一个键或一些垃圾值。你可以这样捕捉我:
for (var i in my_array) {
if (my_array.hasOwnProperty(i)) {
(function(capturedI) {
setTimeout(function() {
do_something_with_data(my_array[capturedI]);
});
})(i);
}
}
你也不应该对数组使用for..in
循环,因为它比for循环慢一个数量级(尤其是使用.hasOwnProperty
检查),并且没有定义迭代顺序
如果您有jQuery或愿意为旧浏览器添加一些额外的代码,您可以这样做:
my_array.forEach( function( item ) {
setTimeout( function() {
do_something_with_data( item );
}, 1000);
});
使用jQuery:
$.each( my_array, function( index, item ) {
setTimeout( function() {
do_something_with_data( item );
}, 1000);
});
的文档
答案 1 :(得分:2)
问题是您创建的函数对i
变量有一个引用,而不是值的副本,所以当它们出现时他们看到i
就像在那个时间点那样(大概是在数组的末尾)。 (更多:Closures are not complicated)
我建议使用完全不同的方法(下面),但首先,让我们看看如何使现有方法有效。
要执行您尝试执行的操作,使用for
循环,您必须使函数关闭不会更改的内容。通常的方法是使用工厂函数创建超时函数,以便它们关闭工厂的参数。或者实际上,您可以传入数组元素的值而不是索引变量。
for(var i in my_array)
{
if(my_array.hasOwnProperty(i))
{
setTimeout(makeFunction(my_array[i]));
}
}
function makeFunction(entry) {
return function(){
do_something_with_data(entry);
};
}
但是,我可能会对代码进行重组,因此您不必不必要地创建大量的函数对象。相反,使用一个函数,让它接近一个递增的索引:
// Assumes `my_array` exists at this point, and that it
// has at least one entry
var i = 0;
setTimeout(tick, 0);
function tick() {
// Process this entry
if (my_array.hasOwnProperty(i)) {
do_something_with_data(my_array[i]);
}
// Move to next
++i;
// If there are any left, schedule the next tick
if (i < my_array.length) {
setTimeout(tick, 0);
}
}
答案 2 :(得分:0)
这只是猜测。试试吧:
for(var i in my_array)
{
if(my_array.hasOwnProperty(i))
setTimeout("do_something_with_data('"+my_array[i]+"')", 500);
}