ブログネタ
JavaScript に参加中!

珍しく更新頻度が高いですが、前回の記事をチェックしているときに気付いたので、忘れないうちにメモ。

今回の記事は、一般的にこういう使い方も知られています、という内容。

Arrayクラスのメソッドをノードリストのメソッドとして実行

getElementsByTagNameで取ってきたDOMエレメント(HTMLLIElement)の配列風オブジェクトHTMLCollectionや同じくquerySelectorAllのNodeListは、経験上なんとなくArrayクラスのメソッドが使えない気がしてたのですが、(↓並びを逆にしようとする一例)

// li要素列を取得(HTMLCollection)
var els = document.getElementsByTagName('li');

// Arrayクラスのreverseメソッドをelsのメソッドとして実行
Array.prototype.reverse.call(els);  // エラー

非破壊メソッドなら動く

これ↓はHTMLCollectionやNodeListでも動きました。

// 配列化
els = Array.prototype.slice.call(els);

// reverseメソッドを実行
els.reverse();

sliceは引数を渡さないと返り値はそのままという事を利用した配列化です。よくargumentsの配列化で使われる式ですね。

ノードリストの配列化を最短で書くと、

ちなみにArray自身にもArrayクラスのメソッドがあるみたいなので、

els = Array.slice.call(els);

という記述もできるみたい。

分ったこと

HTMLCollectionやNodeListは、Arrayクラスの破壊メソッド(オブジェクト自身を書き換える)はダメでも、非破壊メソッドなら動く。

ちなみに

  • なぜ配列化したいのかというと、Arrayクラスには便利なメソッドが沢山あるから。しかもDOMでアクセスするよりも速いらしいです。
  • HTMLCollectionは動的オブジェクト(例えば取得後でも該当要素を動的に追加すると、HTMLCollectionの要素も増える)、NodeListは静的オブジェクト(取得した瞬間から変化しない)です。
  • 一般的には配列化するときはループでコピーします。
// for
var ar = [];
for (var i = 0; i < els.length; i++) {
  ar[i] = els[i];
}

// while
var i = els.length;
var ar = new Array(i);  // []でもいけますが一応。
while (i--) {
  ar[i] = els[i];
}