このブログのはてなブックマーク数 このエントリーをはてなブックマークに追加

知らなきゃ絶対損するPCマル秘ワザ

知らなくて損したPC情報とかを分かりやすくメモする個人ブログ。
『月,水,金』の週3回更新!(予定)

JS:「querySelectorAll」は「getElementsBy」の簡略版ではない

このエントリーをはてなブックマークに追加
イメージ


こんにちは、さち です。

今回は、JavaScript の備忘録です。

サイト上の要素を取得する時は「querySelectorAll」を使うと
jQuery と似た CSS のような形式で記述ができて超便利です。

『これなら「getElementsBy」は要らないんじゃ?』
と思うんですが、そうはいきません。
「getElementsBy」と「querySelectorAll」では動作に違いがあるのです。




「querySelectorAll」は CSS っぽい動作で簡単&便利

例えば、下記のような HTML があります。
「two」クラスを持つ <div> の中にある <li> をすべて取得してみます(11~14行目)。
<div class="one">
<ul>
<li>1-1</li>
<li>1-2</li>

<li>1-X</li>
</ul>
</div>
<div class="two">
<ul>
<li>2-1</li>
<li>2-2</li>

<li>2-X</li>
</ul>
</div>

「getElementsBy」と「querySelectorAll」、それぞれで取得するとこんな感じ。
//「getElementsBy」を使って取得
var elm = document.getElementsByClassName('two')[0];
var li = elm.getElementsByTagName('li');

//「querySelectorAll」を使って取得
var li = document.querySelectorAll('.two li');

「querySelectorAll」は、CSS のような記述で
直感的かつ簡単に要素を取得できるのがメリット。
CSS を書ける人にとっては神がかった機能です。

『じゃあ、常に「querySelectorAll」使えばよくない?』と思うんですが
残念ながら、それは無理です。
両者では取得できるものが違うためです。




「getElementsBy」と「querySelectorAll」の違い

適当なクラスを「getElementsBy」と「querySelectorAll」それぞれで取得。
取得した要素を調べてみます。
var get = document.getElementsByClassName('class');
var query = document.querySelectorAll('.class');

console.log(get);// HTMLCollection []
console.log(query);// NodeList []

//console.log で種類が表示されない時はこちらで
var get_type = Object.prototype.toString.call(get);
var query_type = Object.prototype.toString.call(query);
console.log(get_type);// [object HTMLCollection]
console.log(query_type);// [object NodeList]

「getElementsBy」は HTMLCollection(HTMLコレクション) を取得して
「querySelectorAll」は NodeList(ノードリスト) を取得しています。

どちらも同じ要素を取得したはずなのに、受け取ったものの種類が異なります。
これが、「getElementsBy」と「querySelectorAll」の決定的な違いです。

何か挙動が違うっぽいことは分かりました。
でも、HTMLCollection と NodeList では一体何が違うの……?




「HTMLCollection」と「NodeList」の違い

例として、下記のようなページを作ってみました。
ボタンをクリックすると、リストに新しい <li> 要素を追加します。
<ul>
<li>かん</li>
<li>かん</li>
</ul>
<button>「みかん」を追加</button>

最初に、「getElementsBy」「querySelectorAll」でそれぞれ <li> を取得。
「length」で要素の数を調べると、当然どちらも「2」です。
では、ボタンをクリックして <li> を追加してから
もう一度、それぞれで要素の数を調べるとどうなるでしょう?(15, 16行目)
//li要素を取得
var get = document.getElementsByTagName('li');
var query = document.querySelectorAll('li');
//取得したli要素の数
console.log('get.length: ' + get.length);// get.length: 2
console.log('query.length: ' + query.length);// query.length: 2

//ボタンをクリックしたらリストに「みかん」を追加
var ul = document.getElementsByTagName('ul')[0];
var button = document.getElementsByTagName('button')[0];
button.addEventListener('click', function() {
var li = document.createElement('li');
li.textContent = 'みかん';
ul.appendChild(li);
alert('get.length: ' + get.length);// get.length: ???
alert('query.length: ' + query.length);// query.length: ???
}, false);

実際に、試してみて下さい。
サンプル


「get.length」は、追加した <li> の分だけ増えていくのに対して
「query.length」は、ずっと「2」のままですね。

「getElementsBy」で取得した
「HTMLCollection」はリアルタイムで更新されるのに対して
「querySelectorAll」で取得した
「NodeList」は取得時点の状態のままということ。
操作画面

この特性から
HTMLCollection は、動的な要素(=生きてる)
NodeList は、静的な要素(=死んでる) などと言われます。

つまり、常に最新の状態を取得したい要素は
「getElementsBy」で一度取得するだけで OK です。

記述形式の違いだけでなく、この特性の差を活かして使い分けたいですね。

ちなみに、ボタンを押した後に
get と query から最後尾の <li>要素 のテキストを取得すると
get の方は、ちゃんと追加した「みかん」が出力されます。
//最後の<li>要素のテキストを取得
var get_text = get[get.length - 1].textContent;
var query_text = query[query.length - 1].textContent;

console.log(get_text);// みかん
console.log(query_text);// かん




まとめ

それぞれのメソッドで何が返ってくるのか表にまとめました。
表

「getElementsBy」で取得すると
HTMLCollection になるという感じで書いてきましたが
「getElementsByName」は NodeList です。
気をつけましょう。

ちなみに、「HTMLCollection」「NodeList」はどちらも配列に見えますが
あくまで「配列のようなもの」であって、純粋な配列ではありません。
そのため、配列のプロパティ,メソッド(forEach等)はほぼ使えません。
ややこしいですね……。




このエントリーをはてなブックマークに追加




管理人だけが読めるコメントにする(返信はしません)
【お知らせ】
  • コメントは承認制です。反映に時間がかかります。
  • スパムコメント防止のため一部ホストを規制中です。
  • URLを含む投稿はできません。必要な場合は最初のhを削って下さい。
  • 記事に直接関係ない個人のトラブルにはお答えできません。
  • Android は使用経験がないので質問を頂いても答えられません。
  • その他詳細はこちら





記事別の週間アクセス数ランキングです。こちらの記事もぜひ読んでみて下さい。

2008-2019 知らなきゃ絶対損するPCマル秘ワザ  無断転載禁止

ブログパーツ