10

次のHTML/Javascriptコードのスニペットを確認してください。

<html>
<head>
<script type="text/javascript">
var alerts = [];
for(var i = 0; i < 3; i++) {
    alerts.push(function() { document.write(i + ', '); });
}

for (var j = 0; j < 3; j++) {
    (alerts[j])();
}

for (var i = 0; i < 3; i++) {
    (alerts[i])();
}
</script>
</head><body></body></html>

これは以下を出力します:

3, 3, 3, 0, 1, 2

これは私が期待していたものではありません-私は出力を期待していました0, 1, 2, 0, 1, 2,

私は(誤って)配列にプッシュされている無名関数がクロージャーとして動作しi、関数の作成時に割り当てられた値をキャプチャすると想定しましたが、実際にiはグローバル変数として動作しているように見えます。

このコード例のスコープに何が起こっているのiか、そして無名関数がその値をキャプチャしていない理由を誰かが説明できますか?

4

2 に答える 2

8

スコープは、変数が定義されている関数です(変数がない場合を除き、グローバルです)。

渡す匿名関数は、親関数の(ここでもグローバル)スコープで定義された変数にアクセスしています。

実際の閉鎖が必要です。

alerts.push(
    function (foo) { 
        return function() { 
            document.write(foo + ', ');

        }
    }(i)
);
于 2010-04-28T22:00:11.390 に答える
6

Javasriptでは、唯一の「興味深い」字句スコープ境界は関数本体です。関数内のどこかで宣言されたもの(まあ、別のネストされた関数以外のどこでも!)は同じスコープにあります。宣言が解釈される方法についてもいくつか奇妙なことがあります。

匿名関数はクロージャーとして機能しますが、インスタンス化された各関数は同じ「i」を共有します。私が使用するトリックは、関数の別のレイヤーを追加することです。

for (var i = 0; i < whatever; i++) {
  (function(idaho) {
    whatever(function() { alert("my own private " + idaho); });
  })(i);
}

ある時点で、すべてのブラウザが新しい「let」ステートメントをサポートするようになることを願っています。これは、基本的に同じことを行うための、より短く、奇妙に見えない方法です。

于 2010-04-28T21:58:48.183 に答える