19

Web 上の 1 つまたは 2 つの場所で新しいスコープを誘導する for ループ内の無名関数を見たことがあります。

例えば:

var attr, colors = ['green','blue','red'];

for ( attr = 0; attr < colors.length; attr++) {
    (function() {
        var colorAttr = colors[attr];

        // do something with colorAttr
    })();
}

forループ内のスコープをきれいに保つことと関係があることは理解していますが、これはどのような状況で必要ですか? for ループ内で新しい var を宣言する必要があるすべての場所でこれを行うのは良い習慣でしょうか?

4

2 に答える 2

39

2021 アップデート

var変数を宣言する唯一の方法でした。しかし、現在、この問題をより良い方法で解決するconstとがあります。letこれらの変数宣言は、バインド先のスコープとしてループを尊重します。つまり、次のスニペットは正常に機能し、これらの値をキャプチャする匿名関数は必要ありません。

const colors = ['green', 'blue', 'red'];

for (let i = 0; i < colors.length; i++) {
    const color = colors[i];
    setTimeout(function() {
        alert(color);
    }, i * 1000);
}

以下は、この質問に対する 2012 年の最初の回答です。


ループの一部として、すぐには実行されない内部関数がある場合。

var i, colors = ['green', 'blue', 'red'];

for (i = 0; i < colors.length; i++) {
    var color = colors[i];
    setTimeout(function() {
        alert(color);
    }, i * 1000);
}

// red
// red
// red

ループの中にありvar colorますが、ループにはスコープがありません。実際には、すべてのループ反復で使用される変数は 1 つだけです。そのため、タイムアウトが発生すると、それらはすべて同じ値、つまりループによって設定された最後の値を使用します。

var i, colors = ['green', 'blue', 'red'];

for (i = 0; i < colors.length; i++) {
    (function(color) {
        setTimeout(function() {
            alert(color);
        }, i * 1000);
    })(colors[i]);
}

// green
// blue
// red

これは、各反復で値を関数の引数にキャプチャし、スコープを作成します。colorこれで、各関数は、そのループ内で作成された関数が後で実行されたときに変更されない独自のバージョンの変数を取得します。

于 2012-12-20T17:08:53.973 に答える
3

あなたはほとんどそこにいます。値を引数として自己呼び出し関数に渡す場合、スニペットでのみ意味があります。そうすれば、その変数を独自のスコープ オブジェクト内に格納できます。attr

(function( attr ) {
    var colorAttr = colors[attr];

    // do something with colorAttr
})( attr );

これで、アクティベーション オブジェクトそれぞれのレキシカル環境レコード(ES3 および ES5 スコープ オブジェクト) には、背後にある値のエントリが含まれるattrため、そのClosuredになります。

于 2012-12-20T17:07:11.820 に答える