1

オブジェクトの配列をループしていますが、奇妙な動作が発生しています。これが私のコードです:

  window.onload = function () {

    document.getElementById('btnAdd').onclick = function () {
        add("button");
    };
    function add(type) {
        var names = {};
        names['one'] = { id: "Button 1",msg:"#1" };
        names['two'] = { id: "Button 2", msg: "#2" };
        names['three'] = { id: "Button 3", msg: "#3" };
        //Create an input type dynamically.
        function addOnClick(element, currentName) {
              element.onClick = function () {
                 alert("button is " + names[currentName].msg);
            };
          };       

        for (name in names) {
            var element = document.createElement("input");

            element.type = type;
            element.value = names[name].id; 
            element.name = name;  
             addOnClick(element,name);

            var foo = document.getElementById("fooBar");
            //Append the element in page (in span).  
            foo.appendChild(element);
        }
    }
};

html は次のとおりです。

 <p>
<input type="button" id="btnAdd" value="Add Buttons" />
<p id="fooBar">Buttons:   </p>

</p>

これをブラウザで実行し、[ボタンの追加] ボタンをクリックすると、3 つのボタンが作成され、適切な名前が付けられます。しかし、3 つの新しいボタンのいずれかをクリックすると、アラート ボックスに常に「ボタンは #3」と表示され、その理由がわかりません。onClick イベントが配列の最後の項目のみを覚えている理由を誰かが説明できますか? ありがとう

4

3 に答える 3

4

あなたはjavascriptのクロージャキャプチャのルールの餌食になっています。のコピーは1つだけでnameonclick起動するとコレクションの最後のname値になりますnames。これを解決するにfunctionは、の現在の値をキャプチャする新しいスコープを作成する必要がありますname

var addOnClick = function(currentName) { 
  element.onclick = function() { 
    alert("button is " + names[currentName].msg);
  };
};
addOnClick(name);

編集

onclickまた、 notを使用する必要がありますonClick。ここで重要なのは

フィドル: http: //jsfiddle.net/Nzf3p/

于 2013-03-12T17:34:05.363 に答える
2

これは、クロージャが Javascript で動作する方法 (ローカル変数のキャプチャ) によるものです。割り当てられる無名関数element.onclickは次のとおりです。

function () { 
    // Note this is a function
    alert("button is "+ names[name].msg);
};

ここで、 の値はname、ループ内で検出された最後の値 (最後の要素) にバインドされます。基本的に、ループ内は、外側のループでname使用されるメモリ位置を指します。nameその場所は常に更新され、最後に value を指しますthree。これを回避するには、 の値を保持する追加の関数 (新しいスコープを作成する) が必要ですnamenameこれにより、その新しい関数にローカルなバージョンが作成されるため、保持されます。

//A self-invoked function, into which you pass name. preservedName is the preserved
//value of name, which is local to the scope of this self-invoked function.
(function(preservedName) {
    element.onclick = function() {
        alert("button is " + names[preservedName].msg);
    };
})(name);
于 2013-03-12T17:35:45.977 に答える
1

問題は、onclick ハンドラー用に作成しているクロージャーが原因です。

element.onclick = function () { // Note this is a function
            alert("button is "+ names[name].msg);
        };

関心のある名前を渡す関数でラップする必要があります。

addOnClickToElement(element,name);

次に、この名前付き関数を「add」と同じスコープに追加して、namesアクセスできるようにします。

function addOnClickToElement(element,name) { // Note this is a function
    element.onclick = function(){alert("button is "+ names[name].msg);};
}
于 2013-03-12T17:37:42.877 に答える