JavaScript
Chrome
es6

querySelectorAllで帰ってきたNodeListを外部ライブラリを使わずにforEachしたい

More than 1 year has passed since last update.


You Don't Need jQuery とは言うものの

You Don't Need jQuery をみて気になるのが、forEachの書き方。querySelectorAllで帰ってくるNodeListは配列ではなくオブジェクトなので、JavaScriptのforEachが使えない。

そこで登場するのが

Array.prototype.slice.call

これで、配列っぽいオブジェクトが配列扱いになるらしい。配列っぽいオブジェクトって何?

試しに文字列をいれてみる

Array.prototype.slice.call("ab") 

> ["a", "b"]

となる。ただ素のオブジェクトを入れても

Array.prototype.slice.call({0:"value1",1:"value2"}) 

> []

にしかならない。

試しに、lengthをもった、数字がキーのオブジェクトを作って、それを配列化してみよう

Array.prototype.slice.call({0:"value1",1:"value2",length:2}) 

> ["value1", "value2"]

期待通り。どうも、Length をみて、[0][1]と切り出しているだけっぽい。Lenghと添字アクセスが可能だから文字列が配列に変換できたっぽいね。ということで、手作業で配列っぽいオブジェクトは作れる。


本題のNodeListのforEach。

「ページの中のアンカーのhrefを全部出力するってワンライナー」はこうかける

Array.prototype.slice.call(document.querySelectorAll("a")).forEach( function(e){ console.log(e.href)})

長い。メソッド深すぎ、タイプ多すぎ。読みづらい。

配列に変換したいのではなく、foreEachを使いたいだけなんだから、一足飛びにforEachをcallしてみよう。foEachをCallすると、第一引数にNodeListを直接ぶち込んで、第二引数でcallbackを指定できる。

Array.prototype.forEach.call(document.querySelectorAll("a"), function(e){ console.log(e.href)})

ちょっと短くなった。sliceって単語が出てこないだけ見通しがいい。

いまどきのブラウザは、Arrow Function もサポートし始めているから、スペルミスの多いfunction は省略しちゃおう。

Array.prototype.forEach.call(document.querySelectorAll("a"), e => console.log(e.href))

さらに短くなった。Array.prototypeも面倒だ。prototypeが打ちづらい。

[].forEach.call(document.querySelectorAll("a"), e => console.log(e.href))

さらに短くなった。

ES6になると、配列化とmapの両方をやってくれる、Array.fromというメソッドがある。まぁ親切。これ最強。

Array.from(document.querySelectorAll("a"),  e => console.log(e.href))

手元の Chromeバージョン 50.0.2661.94 (64-bit)では動いている。

ちなみに第二引数で処理されるのはforEachではなくmapなので、returnすれば、配列に変換できる。

Array.from(document.querySelectorAll("a"),  e => {return e.href;})

「ページ内のアンカーのhrefを配列にして、それを改行でjoinして出力」くらいが事務用途で便利。

(コンソールからコピペした時に余計なものがついてこない)

console.log(Array.from(document.querySelectorAll("a"),  e => {return e.href;}).join("\n"))