0

準備ができたコールバックで、要素のすべての子 div に onmouseenter 関数を設定しようとしています。したがって、ボディのオンロードは

    function ready(){
      for(var i=0;i<document.getElementById("pieces").childNodes.length;i++){
    var n=document.getElementById("pieces").childNodes.item(i);
    n.onmouseenter=function(){showBorder(n);};
    n.onmouseleave=hideBorder;
     }
    }

ただし、onmouseenter 関数セットを取得するすべての div は、ループの最後に発生する n の値を使用します。コールバックが設定された時点で、各 onmouseenter が n の値を使用するようにします。

私に何ができる?前もって感謝します

4

2 に答える 2

1

問題は、ハンドラーが同じ single にバインドされていることnです。したがって、n変更するnすべてのハンドラが変更されます。

できることは、反復ごとに実行される即時関数にn渡すことによって「ローカライズ」することです。nこれにより、関数の ではなく、即時関数の にnバインドされた各ハンドラーが作成されます。nnready

function ready() {
    var n;
    for (var i = 0; i < document.getElementById("pieces").childNodes.length; i++) {

        //the local n takes precedence over the outer n
        //therefore any use of n in the immediate function refers to the local n
        (function(n) {

            //you can actually name the variable anything you want
            //but to override the outer n, we use n for our local n

            n = document.getElementById("pieces").childNodes.item(i);
            n.onmouseenter = function() {
                showBorder(n);
            };
            n.onmouseleave = hideBorder;
        }(n));
    }
}​
于 2012-06-28T03:49:09.230 に答える
0

JavaScriptには関数レベルのスコープがあるため、ループ内の変数の宣言n(toの割り当てではない)は、実際には関数の先頭に引き上げられます。document.getElementById('pieces').childNodes.item(i)nforready

これを理解するために、JavaScriptエンジンが実際にコードを解釈する方法であるため、コードが実際に次のように記述されていると想像してください。

function ready() {
    var i, n;
    for (i = 0; i < document.getElementById('pieces').childNodes.length; i++) {
        n = document.getElementById("pieces").childNodes.item(i);
        n.onmouseenter = function () { showBorder(n); };
        n.onmouseleave = hideBorder;
    }
}

のプロパティfunction () { showBorder(n); }を割り当てると、無名関数が実際に実行されたときに、作成時、つまり関数が呼び出されたときにスコープ内にあったすべてのデータにアクセスできるようにクロージャが作成されます。したがって、これらのメソッドはすべて、実行が完了するまでに、と同等の値を持つ変数への参照を持ちます。nonmouseenterreadyonmouseenternreadydocument.getElementById('pieces').childNodes.length

次のコードスニペットをお勧めします。

function ready() {
    var pieces, i, l, n;
    pieces = document.getElementById('pieces').childNodes;
    for (i = 0, l = pieces.length; i < l; i++) {
        n = pieces.item(i);
        n.addEventListener('mouseover', (function (m) {
            showBorder(m);
        })(n), false);
        n.addEventListener('mouseout', hideBorder, false);
    }
}
  1. 関数コンテキスト内でスコープについて混乱しないように、スコープの上部ですべての変数を宣言します。
  2. document.getElementById('pieces').childNodes 一度ルックアップし、そのメモリ位置をpieces変数に割り当てて、そのノードのセットを参照する必要があるたびに別のルックアップを回避します。
  3. forループ内の比較ステートメントは反復ごとにpieces.length実行されるため、検索を繰り返す代わりに、変数に1回割り当てて、lその変数を毎回参照します。
  4. DOM要素のメソッドの使用はon<event>、ほとんどの場合、イベントハンドラーを割り当てるための最悪の方法です。これは、特定のDOM要素に登録できる関数は常に1つだけであるためです。このaddEventListenerメソッドは、代わりにこのメソッドを使用する古いバージョンのInternet Explorerをユーザーが使用することを期待しない限り、ハンドラーを割り当てるための推奨されるattachEvent方法です。
  5. mouseenterおよびイベントは、mouseleave標準のDOMイベントではなく、古いバージョンのInternetExplorer用にMicrosoftによって追加されたカスタムイベントでした。これらはDOMレベル3仕様に追加され、FirefoxとOperaはこれらのイベントのサポートを導入しましたが、Webkitはまだそれらをサポートしていません。
于 2012-06-28T04:47:01.530 に答える