4

問題のコード:

    function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function (num) {
            return function () {
                alert(num);
            };
        }(i);
        document.body.appendChild(link);
    }
  }
  window.onload = addLinks;

私の問題は、返された関数がクロージャーであり、変数numがグローバル変数であるため、関数が実行されるたびnumに、古い値を置き換える現在の値を保持し、その値でどこでも自動的に更新する必要があるためです。しかし、これは起こっていません。各リンクをクリックすると、異なる値が得られます。なぜこうなった?

4

5 に答える 5

2

num無名関数によって閉じられます。function (num) { return function () {}}(i)はそのまま内部関数に渡され、その時点での の値iに基づいて新しい関数が返されます。i

クリック コールバックで の最大値を常に警告するようにしたい場合はi、実際にはさらに簡単です。

link.onclick = function () {
    alert(i);
}

function (var varname)単に無効な構文です。

于 2013-02-21T16:23:31.097 に答える
1

考えてみてください: 次のような 3 つのリンクがあるとします。

<a href="#">0</a>
<a href="#">1</a>
<a href="#">2</a>

クリックしたときに番号を警告するようにするには、次のようにします。

var links = $('a');
for (var i = 0; i < links.length; i++) {
    links[0].onclick = function () {
        alert(i);
    }
}

たとえば、最初のリンクにクリック ハンドラーを割り当てたので、クリックするi = 0とアラート0が表示されることを一見すると予想できます。ただし、クリックすると、実際にはアラートが表示されます3

あなたはそれを自分で言った、あなたのコードは閉鎖を作成しています。上記のコードが行うことは、各リンクのクリック イベントに関数ハンドラーを割り当てることです。これらの各関数ハンドラーは、変数への参照を維持していますi(注: 現在の値ではありません!)。

関数ハンドラーを割り当てる時点では、実際には値iが何であるかを評価しません (必要がないため)。クリックすると、ああ、それは値iが何であるかをチェックして警告するときです。

リンクをクリックするまでに、forループは長い間終了し、 が表示さi = 3れます。これがクリック ハンドラーのアラートです。

于 2013-02-21T16:29:55.557 に答える
0

関数の後の (i) を見てください。このタイプの表記は、自己呼び出し関数専用です。関数を期待しているのに対し、link.onclick = a number を設定しているかのようです。以下を簡単に使用できます。

    link.onclick = function (event) {
        event.preventDefault();
        alert(i);
    };

デフォルトでは、クリック関数はパラメータとして「イベント」を受け取ることに注意してください。イベントの preventDefault() メソッドを必ず呼び出してください。そうしないと、DOM がバブルアップし、アンカー要素の性質によりポストバックがトリガーされます。

于 2013-02-21T16:23:21.080 に答える
0

num変数がどこから来たのか、どのように使用されているのかを説明していません。の現在の値を警告するつもりだと思いますi。クリック ハンドラーはイベント オブジェクトをパラメーターとして受け取るので、次のように試してみます。

function addLinks () {
for (var i=0; i<5; i++) {
    var link = document.createElement("a");
    link.innerHTML = "Link " + i;
    link.onclick = function (event) {
            alert(i);
    };
    document.body.appendChild(link);
}
}
window.onload = addLinks;
于 2013-02-21T16:26:44.740 に答える
0

これは奇妙で、閉鎖について私が知っていると思っていたことと一致しません。addLinks唯一の変更点(質問の最初のバージョン):

link.onclick = function (num)

link.onclick = function ()

num期待どおりの結果が得られます。つまり、リンクがクリックされるたびに、グローバル変数の実際の値が警告されます。

おそらく、インタープリターがクロージャーに遭遇したときにクロージャー内で参照されるスコープ変数を保存する方法に関係しています。変数がクロージャーで参照されると、その変数の最も近い出現箇所が現在のスコープから上に向かって検索されます。

最初のケースでは、(宣言後に複数回呼び出される関数への)パラメーターとして定義されますが、毎回異なる値を持つため、クロージャーごとに異なるスコープ値が「記憶」されます。

num2 番目のケースでは、見つかった唯一のオカレンスはグローバル スコープ内にあり、どのハンドラーが呼び出されたかに関係なく、実際の値が使用されています。

于 2013-02-21T16:45:51.953 に答える