1

重複の可能性:
Javascript の悪名高いループの問題?

私は小さな問題を抱えています。見つけられないように見えるので、ここにどのような種類のロジックが欠けているかを理解していただければ幸いです。

以前の操作の結果を含む配列があります。配列が次のようになっているとしましょう:

var results = [0, 1];

次に、いくつかのボタンを作成する一連のコードがあり、forループ内で、配列の位置に応じて、これらのボタンに異なる機能を割り当てます。問題は、何らかの理由で、作成されたすべてのボタン (この場合は 2 つ) が、配列の最後の値に割り当てられた関数で出力されることです (この場合、最初の 0 と 0 ではなく、両方が 1 つとして出力されます)。 2 番目の 1)

これはコードです:

for (var i = 0; i < results.length; i++) {
    var br2 = b.document.createElement("br");
    var reslabel = b.document.createTextNode(Nom[results[i]].toString());
    var card = document.createElement("input");
    card.type = "button";
    id = results[i]; // this is the problematic value. 
    card.onclick = newcard; // this function will use the above value.
    card.value = "Show card";
    divcontainer.appendChild(br2);
    divcontainer.appendChild(reslabel);
    divcontainer.appendChild(card);
} 

このコードは、配列内の要素と同じ数のボタンを生成し、それぞれに適切なラベルを付けます (別の配列からラベルを取得します)。すべてがまったく問題ありません。次に、ボタンをクリックします。すべてのボタンでnewcard機能を実行する必要があります。その関数にはid変数が必要なので、この場合は次のようにする必要があります。

  • 最初のボタン:値 0 のnewcard変数を使用して実行id
  • 2 番目のボタン:値 1 のnewcard変数を使用して実行id

しかし、両方のボタンがid1 として実行されます...なぜですか?

それは非常に単純かもしれませんし、私のタイムゾーンではすでにかなり遅いかもしれません:-) とにかく、コメントをいただければ幸いです。この辺で色々と勉強中…

ありがとう!

編集して newcard の定義を追加します。

function newcard() {
    id = id;
    var toerase = window.document.getElementById("oldcard");
    toerase.innerHTML = "";
    generate();
}

the function generate will generate some content using id. Nothing wrong with it, it generates the content fine, is just that id is always set to the last item in the array.

4

2 に答える 2

3

Youridはグローバル変数であり、ループが終了すると配列の最後の値に設定されます。イベント ハンドラー コードが実行され、 の値を要求するとid、最後の値が取得されます。

現在をキャプチャしてそれを渡すクロージャを作成する必要がありますresults[i](これは非常に一般的な落とし穴です。Javascript の悪名高い Loop problem?を参照してください)。newcardは非常に単純で、id実際に で使用されるため、id をパラメーターとして受け取るようにgenerate変更できます。その後、もうgenerate必要ありません。代わりにこれを行うことができます:newcard

card.onclick = (function(id) { 
    return function() { 
        window.document.getElementById("oldcard").innerHTML = "";
        generate(id);
    }; 
}(results[i]));

これが行うことは、 current に渡される関数を定義してすぐに呼び出すことですresults[i]onclick実際のハンドラーになる別の関数を返します。idその関数は、外側の関数 (クロージャーと呼ばれる) のパラメーターにアクセスできます。ループの反復ごとに、新しいクロージャーが作成され、それぞれが個別idに使用できるようにトラップされます。

于 2012-12-22T01:08:49.080 に答える
3

先に進む前に、bfavarettoに、私が完全に逃したスコーピングの詳細を説明してくれて、本当に感謝しています。あなたが抱えていた問題に加えて、あなたはスコーピングにも苦しんでいたようです.

とにかく、これはうまくいく例です。一部のブラウザーではサポートされていない可能性がある forEach を使用しています。ただし、悲しみを与えていたスコーピングの煩わしさのいくつかを回避します。

<html>
<body>
<script>
var results = [0,1];
results.forEach( function(result) {
    var card = document.createElement("input");
    card.type = "button";
    card.onclick = function() {
        newcard( result );
    } 
    card.value = "Show card";
    document.body.appendChild(card);
}); 

function newcard(x) {
   alert(x);
}
</script>
</body>
</html>

従来のループに固執する場合は、bfavaretto の回答を参照してください。

于 2012-12-22T00:41:28.233 に答える