概要
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でいいかなという結論でお願いします