JavaScriptには関数レベルのスコープがあるため、ループ内の変数の宣言n
(toの割り当てではない)は、実際には関数の先頭に引き上げられます。document.getElementById('pieces').childNodes.item(i)
n
for
ready
これを理解するために、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); }
を割り当てると、無名関数が実際に実行されたときに、作成時、つまり関数が呼び出されたときにスコープ内にあったすべてのデータにアクセスできるようにクロージャが作成されます。したがって、これらのメソッドはすべて、実行が完了するまでに、と同等の値を持つ変数への参照を持ちます。n
onmouseenter
ready
onmouseenter
n
ready
document.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);
}
}
- 関数コンテキスト内でスコープについて混乱しないように、スコープの上部ですべての変数を宣言します。
document.getElementById('pieces').childNodes
一度ルックアップし、そのメモリ位置をpieces
変数に割り当てて、そのノードのセットを参照する必要があるたびに別のルックアップを回避します。
for
ループ内の比較ステートメントは反復ごとにpieces.length
実行されるため、検索を繰り返す代わりに、変数に1回割り当てて、l
その変数を毎回参照します。
- DOM要素のメソッドの使用は
on<event>
、ほとんどの場合、イベントハンドラーを割り当てるための最悪の方法です。これは、特定のDOM要素に登録できる関数は常に1つだけであるためです。このaddEventListener
メソッドは、代わりにこのメソッドを使用する古いバージョンのInternet Explorerをユーザーが使用することを期待しない限り、ハンドラーを割り当てるための推奨されるattachEvent
方法です。
mouseenter
およびイベントは、mouseleave
標準のDOMイベントではなく、古いバージョンのInternetExplorer用にMicrosoftによって追加されたカスタムイベントでした。これらはDOMレベル3仕様に追加され、FirefoxとOperaはこれらのイベントのサポートを導入しましたが、Webkitはまだそれらをサポートしていません。