2

クロージャーについて読んでいますが、これら 2 つのコード スニペットの違いを理解するのに苦労しました。

var myElements = [ /* DOM Collection */ ];

for (var i = 0; i < 100; ++i) {
    myElements[i].onclick = function() {
        alert( 'You clicked on: ' + i );
    };
}

上記のコードはi、onclick ごとに 99 としてのみ表示されます。

function getHandler(n) {
    return function() {
        alert( 'You clicked on: ' + n );
    };
}

for (var i = 0; i < 100; ++i) {
    myElements[i].onclick = getHandler(i);
}

上記のコードは、要素のクリック イベントごとに 'i' の正しい値を表示します。

最初のものに の正しい値が表示されない理由がわかりませんi。そうでない場合、2 番目の値が正しい値を表示するのはなぜですか??

彼らはこのリンクから取られました

4

7 に答える 7

4

最初のものに の正しい値が表示されない理由がわかりませんi

これは、クロージャが のをキャプチャするのiではなく、実際のローカル変数をキャプチャするためですi。の値を変更しi続けると、同じ変数をまだ使用しているため、クロージャーはそれらの変更を認識します。

そうでない場合、2 番目の値が正しい値を表示するのはなぜですか??

2番目のものでは、クロージャーはローカル変数をキャプチャしているため、nその後変更されることはありません。(後でgetHandler完全に新しいローカル変数を持つように呼び出しますn。これは、クロージャーだけでなく、再帰のサポートにも重要です。そうしないと、関数への異なる呼び出しが誤って互いの変数を台無しにする可能性があります!)

于 2012-10-19T14:24:21.600 に答える
1

どちらも、クリックが発生したときに値を表示します。

最初のものには が 1 つしかなくi99クリックが発生したときです。

2 つ目では、が呼び出されるnたびに新しいfor があります。getHandler

于 2012-10-19T14:23:51.777 に答える
0

「i」変数はスコープにバインドされ、「i」が正しい値を持つ瞬間に評価される関数で新しいスコープを作成できます

この動作を実装できます。

var myElements = [{}, {}];

for (var i = 0; i < 2; ++i) {
    myElements[i].onclick =
        function(i) {
            return function() {
                alert( 'You clicked on: ' + i );
            }
        }(i); // <- This behavior is the important one
}

ご挨拶

于 2012-10-19T14:46:39.950 に答える
0

最初の例では、 への参照を使用して onclick 関数がループ内に作成されiますが、クリックが発生するまで実行されません。クリックがトリガーされると、関数が実行iされ、現在 99 に設定されている が読み取られます。

2 番目の例でgetHandler(i)は、 がすぐに実行され、 を参照する関数が返されnます。(これが、返された関数がクロージャと呼ばれる理由です: 渡された値を「閉じた」状態です)。この新しい関数スコープでnは、渡された値 (探している値) と同じです。

于 2012-10-19T14:25:18.517 に答える
0

関数が呼び出されるまでに の値iが 99 であるため、最初の例ではそれぞれに 99 が表示されます。

i2 つ目は、 (パラメーターを介して)閉じるため、正しい値が表示されますn。これは、whileiが変化し続けn、関数が呼び出された時点の値を保持することを意味します。

于 2012-10-19T14:23:48.590 に答える
0

onclick関数は後で起動される予定です。

最初のケースでは、イベントが発生するまで i の値が失われます。

しかし、2 番目のケースでは、i の値がコピーされ、後で使用できるように保存されます。

于 2012-10-19T14:25:47.247 に答える
0

2 番目の例が機能し、1 番目の例が機能しない理由は、スコープに関係しています。最初の例では、変数iはグローバル スコープ内に格納され、ボタンをクリックすると読み取られます。ループを完了すると、iは 99 です。ループ中にボタン 1 をクリックできた場合は、 の現在の値が何であれ取得されますi。(ちなみに、これは不可能です)。

2 番目の例では、 のコピーがifunction 内に格納されていますが、これはループ内でgetHandler変更しても変更されません。は、返される(名前のない)関数のスコープであり、それが読み取る変数です。igetHandler

于 2012-10-19T14:26:25.803 に答える