Personal tools
You are here: Home ブログ uchida goog.dom.getElementsByTagNameAndClassは配列を返さない
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Categories
JavaScript
Go
Ada
Delphi
junk
 
Document Actions

goog.dom.getElementsByTagNameAndClassは配列を返さない

タグ名やクラス名を指定してエレメントを取得する基本的なメソッドです。
これは極力ネイティブのquerySelectorAllやgetElementsByClassNameを使おうとするので、FireFoxやIE8ではなかなか高速に動きます。
しかしgetElementsByClassNameやgetElementsByTagNameは生きたNodeList(HTMLCollection)を返すので、配列と同じように扱っていると偶に痛い目に会います。(getElementsByClassName()の落とし穴)

※querySelectorAllは静的なNodeListを返すそうです。動的だと思ってました。(querySelectorAllがliveじゃないNodeList返すのはなんで?)

ここまでは別にClosure Library固有の問題ではないのでご存知の方も多いかと思われます。
ではquerySelectorAllもgetElementsByClassNameも実装されていないIE6やIE7でgoog.dom.getElementsByTagNameAndClassがどう動くかというと、こんなコードになっています。

 var els = parent.getElementsByTagName(tagName || '*');

if (opt_class) {
var arrayLike = {};
var len = 0;
for (var i = 0, el; el = els[i]; i++) {
var className = el.className;
// Check if className has a split function since SVG className does not.
if (typeof className.split == 'function' &&
goog.array.contains(className.split(/\s+/), opt_class)) {
arrayLike[len++] = el;
}
}
arrayLike.length = len;
return arrayLike;
} else {
return els;
}

arrayLike変数は実質配列なのにObject型のインスタンスになっています。
これにはgoogleの「クロスブラウザ対応時に余計なバグを埋め込まないよう、絶対にArrayは返さないぞ」という心遣い(?)を感じます。

しかしそんな心遣い(?)も虚しく、生きたNodeListと死んだものとが混在することはすぐに罠となります。
例えば特定のエレメントを削除したくて

var els = goog.dom.getElementsByTagNameAndClass('input', 'text' element);
for (var i = 0, el; el = els[i]; i++) {
goog.dom.removeNode(el);
}
と書いた場合、生きたNodeListが返れば歯抜けになるでしょう。だからといって
var els = goog.dom.getElementsByTagNameAndClass('input', 'text' element);
var el;
while ((el = els[0])) {
goog.dom.removeNode(el);
}
と書くと、死んだNodeListで無限ループ or エラーになるでしょう。

しょうがないので私は

var els = goog.dom.getElementsByTagNameAndClass('input', 'text' element);
for (var i = els.length -1, el; el = els[i]; i--) {
goog.dom.removeNode(el);
}
と書きました。

ちなみにDelphiにはこんなこともあろうかとfor-downto-doという構文があります。どうだ、羨ましかろう。


パフォーマンスのためとはいえこんな基本的な部分にブラウザ依存な罠があることにゾッとします。
何かベストプラクティスはないのでしょうか?

Category(s)
JavaScript
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/uchida/goog-dom-getelementsbytagnameandclass306f914d521730928fd43055306a3044/tbping

Re:goog.dom.getElementsByTagNameAndClassは配列を返さない

Posted by Anonymous User at 2010-09-07 13:53
Array.prototype.slice.call(els, 0);

ではどうでしょうか?
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.