概要
document.getElementById
して、childNodes
プロパティで子要素を取った場合などに返ってくるNodeListはArray-LikeなオブジェクトでArray.filter
が使えないのでfilterする方法をメモ
filter以外のメソッドを使いたい場合も同じことをすれば大体使えるはず
前提
下記のselect
のoption
要素を取ってくる
その際にselect
のchildNodes
でoption
のリストを得ようとするとoption
要素以外も取れてしまうので、childNodes
でNodeList
を得た後に、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.from
でobject
を配列に変換してるところが違う
配列に変換された後だったら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
でいいかなという結論でお願いします