前回の記事で、Live・非Liveなオブジェクトについて記載しました。
今回は、Liveなオブジェクトでのlengthの使用方法について記載します。
目次
1. Liveなオブジェクトとlengthプロパティのおさらい
前回の記事より、Liveなオブジェクトでは、セレクタを使用してある要素を取得後に、その要素に関連するDOMに変化があった場合(子要素の追加など)、その変更内容が変数にも反映されます。
前回の記事からの引用になりますが、以下の例のjavascriptの③、⑤でlengthプロパティで返る値に注目してください。
例:divに3つ目の子要素pを追加する
html
1 2 3 4 |
<div id="div-any-p"> <p>段落1</p> <p>段落2</p> </div> |
javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// ① 親要素を取得 var parentDiv = document.getElementById("div-any-p"); // ② 子要素のp要素を取得(HTMLCollectionオブジェクト) var selectElems = parentDiv.getElementsByTagName("p"); // ③ 子要素Pの数を出力(p要素の数:2) console.log("p要素の数:%d", selectElems.length); // ④ 新たにP要素を作成し、子要素として追加 var newElementP = document.createElement("p"); parentDiv.appendChild(newElementP); // ⑤ 子要素Pの数を出力(p要素の数:3) console.log("p要素の数:%d", selectElems.length); |
③ と ⑤ で 子要素の数が増えているのが分かります。
2. lengthプロパティを使用する際の注意点
先のほどの例から、Liveなオブジェクトを参照している、lengthプロパティの値は、DOMが変化することにより、動的に変化することが分かりました。
なので、仮にfor文でLiveなオブジェクトを参照している変数のlength分処理を行う場合、処理内容によっては無限ループになる可能性があります。
先ほどの例のjavascriptの一部を変更して、以下のようにすると無限ループになります。
1 2 3 4 5 6 7 8 9 10 11 |
// ① 親要素を取得 var parentDiv = document.getElementById("div-any-p"); // ② 子要素のp要素を取得(HTMLCollectionオブジェクト) var selectElems = parentDiv.getElementsByTagName("p"); // ③ 要素の追加(無限ループ) for(var i = 0; i < selectElems.length; i++ ){ var newElementP = document.createElement("p"); parentDiv.appendChild(newElementP); } |
③ では、forの終了条件に、Liveなオブジェクト(selectElems)を指定していますが、for内の処理で、selectElems に 子要素を追加しています。
そのため、lengthプロパティで返される値も増えていき、終了条件が満たされません。
また、lengthプロパティの値が変わる ということは、lengthプロパティを使用する度に計算が行われている可能性があります。
そのため、若干のオーバーヘッドがあるかもしれません。
なので、安全に処理を行う場合、for文の終了条件に Liveなオブジェクトを参照している変数のlengthは使用しない方がいいと思います。
上記の処理を書き直すと次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// ① 親要素を取得 var parentDiv = document.getElementById("div-any-p"); // ② 子要素のp要素を取得(HTMLCollectionオブジェクト) var selectElems = parentDiv.getElementsByTagName("p"); // ③ Liveなオブジェクトのlenghtプロパティの値を取得 var elemLength = selectElems.length; // ④ 要素の追加(③時点でのlength数分行われる) for(var i = 0; i < elemLength; i++ ){ var newElementP = document.createElement("p"); parentDiv.appendChild(newElementP); } |
③ で 変数 elemLength に lengthプロパティの値を代入しているので、④ では無限ループにならず処理されます。
3. まとめ
Liveなオブジェクトでのlengthプロパティ扱い方について記載しました。
上記の③の書き方は、一見冗長に見えますが無限ループを回避する重要なコードです。
個人的には、ソースレビュー中に、これはLiveなオブジェクト、こっちは非Liveなど考えたくない(javascriptのどのメソッド・プロパティで返ってくる値がLive・非Liveをjavascriptの仕様書を参照している時間がない)ので、
一律でforの終了条件に直接lengthプロパティを使用しない。
というコーディング規約がいいかなとも思います。