1
function init(list) {
    var result = [];
    for (var i = 0; i<list.length; i++) {
        var item = 'item' + list[i];
        result.push( function() { alert( item + ' ' +list[i] ) } );
    }
    return result;
}
function foo() {
    var list = init([1,2,3]);
    for (var j = 0; j<list.length; j++) {
        list[j]();
    }
}
foo();

脚本警告:

  • item3 未定义
  • item3 未定义
  • item3 未定义
4

3 回答 3

1

到你打电话的时候list[j]();,价值i3(因为for (var i = 0; i<list.length; i++) {意志已经到了尽头。

于 2013-08-02T09:42:54.570 回答
1

i又是一个古老的 + 范围问题;)......解决方案:

function init(list)
{
    var item, result = [];
    for (var i = 0; i<list.length; i++)
    {
        item = 'item' + list[i];
        result.push((function(val, idx)
        {//create this function with its own scope
            return function()
            {//return this function, which has access to val and idx
                alert(val+' '+list[idx]);
            };
        }(i, item));//pass vals of i and item to function, and call it here (IIFE)
    }
    return result;
}

为什么?在给定范围内创建的所有函数都可以访问在该更高范围内声明的任何变量。因此,您正在推动的功能result确实可以访问i,itemlist. 他们有权访问,但不拥有这些变量的自己的副本
在 for 循环的每次迭代中,i 都会递增,因此它是 0、1、2、3。当它的值达到 3 时,它的值不再< list.length是循环结束。但是在您创建的函数内部list[i]计算结果为list[3],这是未定义的。

这同样适用于item,变量在init函数中声明,它在每次迭代中也被重新分配,因此无论您调用哪个创建的函数,它们都将引用最后分配给的任何内容item:在您的情况下为“item3”

我已经发布了一个相当长的答案,详细解释了这一点,并且我也向tag-wiki添加了很多信息。现在,您可以像这样轻松地测试它:

function init(list)
{
    var j, result = [];
    for (var i = 0; i<list.length; i++)
    {
        var item = 'item' + list[i];
        result.push( function() { alert( item + ' ' +list[i] ) } );
        for (j=0;j<=i;j++)
        {
            result[j]();
        }
    }
    alert(i);
    return result;
}

这将提醒类似:

//i = 0
item1 1
//i = 1
item2 1
item2 2
//i=2
item3 1
item3 2
item3 3
//outside loops, alert i:
3
于 2013-08-02T09:45:05.977 回答
0

因为您存储在数组中的内部函数引用变量而不是每次迭代中的值。您可以使用作为参数调用函数,i该参数返回要保留在数组中的函数,并且因为您正在创建一个新函数并且 javascript 函数创建一个新范围并获取参数的值,所以它的位置为内存i指向您调用该函数的那一刻;

function init(list) {
    var result = [];

    for (var i = 0; i<list.length; i++) {
        var item = 'item' + list[i];
              result.push( (function (i){ return function() { alert( item + ' ' +list[i] )};})(i))
    }
    return result;
}
function foo() {
    var list = init([1,2,3]);
    for (var j = 0; j<list.length; j++) {
        list[j]();
    }
}
foo();
于 2013-08-02T09:56:58.830 回答