5

以下のコードでは、追加のパラメーターを受け取る image.onclick のイベント ハンドラーを定義しようとしていることがわかります。JavaScript がこのようにスコープを定義することを期待して while ループ内でこれらのパラメーターを宣言していましたが、そうではありません。基本的に、ここにあるすべてのイベント ハンドラーは、変数 id と section_id に与える最後の値を取得しています。これらのハンドラーを動的に生成したい状況を処理する方法についてのアイデアはありますか?

function handlePicturesResult(){
    if (req.readyState == 4) { // Complete
        if (req.status == 200) { // OK response

            var el = document.getElementById('pictureHolder');
            while( el.hasChildNodes() ){
                el.removeChild(el.lastChild);
            }

            var tempObject = JSON.parse(req.responseText);
            var pictures = tempObject.images;
            var i=0;

            while(i<pictures.length){

                var picIndex = i;

                var image= new Image(120,80);
                image.src = 'images/' + pictures[i].url;
                image.width = 120;
                image.height = 80;
                var id = pictures[picIndex].id;
                var section_id = pictures[picIndex].sectionId;
                image.onclick = function(event){
                    deleteImage(event,id,section_id);
                }


                var txtNode = document.createTextNode(pictures[picIndex.valueOf()].id); 
                el.appendChild(image);
                el.appendChild(txtNode);
                i++;
            }
        } else {
        alert("Problem: " + req.statusText);
        }
    }

}
4

3 に答える 3

14

クロージャーによって解決されるさらに別の問題!

image.onclick = function(id, section_id){
    return function(event) {
        deleteImage(event,id,section_id);
    }
}(id, section_id);

外側の関数はすぐに実行され (最後に括弧があることに注意してください)、内側の関数を返します。この関数は、ループの反復での変数のコピーをスコープに保持します。

JavaScript は非オブジェクト変数を値渡しするため、外側の関数にidandsection_idを渡すことで、その関数内にそれらのコピーを作成します。内部関数を作成して返すと、その内部関数は、作成時にスコープ内にあったすべての変数をスコープ内に保持します (これは、 とのローカル変数のコピーを含みます)。独自のスコープを持つ内部関数は、その要素のイベント ハンドラーになります。idsection_id

于 2012-06-01T19:59:22.560 に答える
0

これは、関数のスコープに関する理解の欠如に起因する、JavaScript の典型的な問題です。この行で:

deleteImage(event,id,section_id);

に渡されたパラメータが、コールバックが作成された時点でdeleteImageの値を保持する必要があるという理由はありません。変数とは;のスコープにバインドされています。それらはその空間内に存在する変数であり、それぞれのコピーは 1 つしか存在しません。したがって、コールバックが実行されると、それらの特定の変数と、それらが現在参照している値 (ループの最後の反復から) が使用されます。idsection_idhandlePicturesResult

解決策は、ループの反復ごとに変数の値を「保存」するスコープに変数を取得することです。関数は、JS でそのようなスコープを提供するだけです。すでに提供されている優れたソリューションは繰り返しません。別の方法は、繰り返しに jQuery を使用するeachことです。これにより、この問題が再び発生することはありません。

$.each(pictures, function(i, picture) {

    var image= new Image(120,80);
    var id = pictures.id;
    var section_id = picture.sectionId;
    var txtNode = document.createTextNode(id);

    image.width = 120;
    image.height = 80;
    image.src = 'images/' + picture.url;

    image.onclick = function(event){
        deleteImage(event, id, section_id);
    }

    el.appendChild(image);
    el.appendChild(txtNode);

});
  • は配列であると仮定picturesします。
于 2012-06-01T20:15:38.753 に答える
0

クロージャーを使用する必要があります。 https://developer.mozilla.org/en/JavaScript/Guide/Closures

image.onclick = function(id, s_id){
  return function(event){
    deleteImage(event, id, s_id);
  }
}(id, section_id)

JavaScript のスコープは、関数の中括弧内で定義できます。そのため、外部関数に引数を渡して実行させると、必要なループ内の特定の時点でこれらの変数の値が保持されます。

それらがないと、id と section_id の値は常に、最後の反復での値を参照します。

于 2012-06-01T20:01:59.807 に答える