LoginSignup
3
1

More than 5 years have passed since last update.

Array.filterが使えないNodeListに対してフィルターをかける方法

Last updated at Posted at 2018-10-07

概要

document.getElementByIdして、childNodesプロパティで子要素を取った場合などに返ってくるNodeListはArray-LikeなオブジェクトでArray.filterが使えないのでfilterする方法をメモ

filter以外のメソッドを使いたい場合も同じことをすれば大体使えるはず

前提

下記のselectoption要素を取ってくる

その際にselectchildNodesoptionのリストを得ようとするとoption要素以外も取れてしまうので、childNodesNodeListを得た後に、Element以外をfilterする

    <form>
        <label for="food">一番好きな食べ物は?:</label>
        <select id="food">
            <option value="ラーメン">ラーメン</option>
            <option value="餃子">餃子</option>
            <option value="焼き肉">焼き肉</option>
        </select>
        <button type="button" id="btnRegister">決定</button>
    </form>

方法1:Array.prototype.filter.callを使う

Array-Likeなオブジェクトに対して、Arrayのfilter等のメソッドを使いたい場合、callメソッドが使えるらしい

Array.prototype.*.callという風に使う

let select = document.getElementById('food');
let children = select.childNodes;
let selectedOptions = Array.prototype.filter.call(children, node => { return node.nodeType === Node.ELEMENT_NODE; });
console.log(selectedOptions);

ところでcallって何?

callで呼べば、Arrayで使えるメソッドが使えるのはわかったけどそもそもcallって何だよっていうお話

あるオブジェクトに属するメソッドを別のオブジェクトのメソッドのように呼び出したい (すなわち、メソッド中の this キーワードの参照先オブジェクトを別のオブジェクトにしたい) とき、call メソッドを使えば、わざわざ別のオブジェクトのプロパティにそのメソッドを代入せずとも済みます。 例えば、obj.testMethod というメソッドを otherObj のメソッドのように呼び出したいときは、obj.testMethod.call( otherObj ) とすればよいです。

参照:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/call

そのまんまの意味であるオブジェクトで使いたいメソッドがあった時に、いちいちそのオブジェクトにメソッドを用意するの怠いよね?

怠いから代入せずとも使えるようにメソッド用意しといてやったぞ有り難く使え!ってことらしい

有り難や〜

方法2:Array.from(object).filterを使う

さっきと何が違うのかというとまずArray.fromobjectを配列に変換してるところが違う

配列に変換された後だったらfilterメソッドあるから普通に使えるよねというお話

let selectedOptions2 = Array.from(children).filter( node => { return node.nodeType === Node.ELEMENT_NODE; });
console.log(selectedOptions2);

方法3:firstElementChildとnextElementSiblingとwhileを併用

firstElementChildで最初のElement要素を取ってこられる

次の要素はnextElementSiblingで取ってくる

次の要素がない場合はnextElementSiblingにはnullが入ってるのでwhileは終わる

かなり記述が冗長になってしまうし、使う意味を感じないので使わなさそう

let select = document.getElementById('food');
let child = select.firstElementChild;
let children = [];
while (child) {
        if (child.nodeType === Node.ELEMENT_NODE) {
                children.push(child);
        }
        child = child.nextElementSibling;
}
console.log(children);

結局どれを使うのか

速度比較をしてくれている記事を発見したので下記参照

JSのArray.prototype.filter.callとArray.from().filterどっちが早いか

Array.prototype.filter.callでいいかなという結論でお願いします

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1