NodeList オブジェクトは Array.prototype を継承しない
querySelectorAll
が返す NodeList
オブジェクトは Array.prototype
を継承しない為、そのままでは Array.prototype.forEach
を使用できません。
そこで Function.protoype.call
を利用してこれに対応するテクニックがよく使われます。
Array.prototype.forEach.call(document.querySelectorAll('p'), function (element) { console.log(element); });
よく使う機能なら関数化したい、という事でいくつか書いてみました。
(2016/12/22 15:05 追記)
@gaogao_9 さんより「HTML Living Standard では NodeList
に “entries”, “forEach”, “keys”, “values” がある」との情報を頂きました。
Array.prototype.forEach
とは別物ですが、使い勝手は同じだそうです。
console.log(document.querySelectorAll('p').forEach); // function forEach() { [native code] }
console.log(document.querySelectorAll('p').forEach === Array.prototype.forEach); // false (Google Chrome 55.0.2883.87 m の結果)
document.querySelectorAll('p').forEach(function (element, i, elements) {
console.log(element, i, elements, this);
}, []);
Array.prototype
にあるメソッド全ては存在しないので以降は Array.prototype.filter
等、他の関数を汎用化するものと置き換えて下さい。
あるいは、HTML Living Standard を実装していないブラウザ向けとお考え下さい。
汎用関数 forEach (通常版)
よく見るコードです。
function forEach (arrayLike, callbackfn) {
return Array.prototype.forEach.call(arrayLike, callbackfn);
}
汎用関数 forEach (forEachキャッシュ版)
Array.prototype.forEach
を何度も参照するのはプロパティ参照コストが無駄なのでキャッシュしました。
var forEach = (function (_forEach) {
return function forEach (arrayLike, callbackfn) {
return _forEach.call(arrayLike, callbackfn);
};
}(Array.prototype.forEach));
汎用関数 forEach (forEach,callキャッシュ版)
更に Function.prototype.call
もキャッシュしました。
Function.prototype.bind
を利用している為、ES5 (IE9+) を要求しますが、自前で関数式を書く必要がなくなっています。
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
実行サンプル
<p>test1</p>
<p>test2</p>
<p>test3</p>
<p>test4</p>
<p>test5</p>
<p>test6</p>
<script>
'use strict';
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
forEach(document.querySelectorAll('p'), function (element) { console.log(element); });
</script>