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ている関数には、実際にiitemおよびへのアクセスがありlistます。アクセス権はありますが、それらの変数の独自のコピーを所有していません。
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 に答える