JavaScript の for...of 周りとDOMの取得周りのメモ

2021/09/03

jQuery と JavaScript の要素の扱い

jQuery

console.log($("img"));

// jQuery.fn.init(4) [img.img-fluid, img.img-fluid, img.img-fluid, img.img-fluid, prevObject: jQuery.fn.init(1)]
// 0: img.img-fluid
// 1: img.img-fluid
// 2: img.img-fluid
// 3: img.img-fluid
// length: 4
// prevObject: jQuery.fn.init [document]
// [[Prototype]]: Object(0)

JS

const images = document.images;
console.log(images);

// HTMLCollection(4)
// 0: img.img-fluid
// 1: img.img-fluid
// 2: img.img-fluid
// 3: img.img-fluid
// length: 4
// [[Prototype]]: HTMLCollection

const imgTags = document.querySelectorAll('img');
console.log(imgTags);

// NodeList(4)
// 0: img.img-fluid
// 1: img.img-fluid
// 2: img.img-fluid
// 3: img.img-fluid
// length: 4
// [[Prototype]]: NodeList

jQuery は jQueryオブジェクト、 document.images では HTMLCollections、 document.querySelectorAll('img') では NodeList が取得できる。

分割代入と for...of Object.entries()

const imgTags = document.querySelectorAll('img');
for (const [key, val] of Object.entries(imgTags)) { /* 略 */ }
  • imgTags[key, val]の2つの値に分割代入できるようなイテラブルな形ではないので、 Object.entries() でイテラブルな形に変換する
  • 変換されたキーと値の配列をそれぞれ keyval の2つの変数に分割代入する

という流れ。ただ、 imgTags は場合によってはイテラブルな場合もある。

const imgs = document.images;
console.log(imgs)
for (const img of imgs) {
    console.log(typeof img)
    console.log(img)
}

// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​


const imgTags = document.querySelectorAll('img');
console.log(imgTags)
for (const img of imgTags) {
    console.log(typeof img)
    console.log(img)
}

// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// object
// <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​


for (const [key, val] of Object.entries(imgTags)) {
    console.log(typeof key, typeof val)
    console.log(key, val)
}

//string object
// 0 <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// string object
// 1 <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// string object
// 2 <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​
// string object
// 3 <img src=​"https:​/​/​placehold.jp/​640x320.jpg" class=​"img-fluid">​

上述の2番目のケースでは imgTags をそのまま for...of で回しているがイテラブル。

問題となるのは3番目のケースで分割代入する前提で回そうとした場合。

const imgTags = document.querySelectorAll('img');
for (const [key, val] of imgTags) {
    console.log(typeof key, typeof val)
    console.log(key, val)
}

// Uncaught TypeError: .for is not iterable

当然といえば当然ですが、単純な NodeList の imgTagskey, val の2つの値に分割代入しようとしてもそれはできないわけで。

そのため、 not iterable と怒られるわけです。

const imgTags = document.querySelectorAll('img');
console.log(imgTags);

// NodeList(4) [img.img-fluid, img.img-fluid, img.img-fluid, img.img-fluid]
// 0: img.img-fluid
// 1: img.img-fluid
// 2: img.img-fluid
// 3: img.img-fluid
// length: 4
// [[Prototype]]: NodeList

console.log(Object.entries(imgTags));

// (4) [Array(2), Array(2), Array(2), Array(2)]
// 0: (2) ["0", img.img-fluid]
// 1: (2) ["1", img.img-fluid]
// 2: (2) ["2", img.img-fluid]
// 3: (2) ["3", img.img-fluid]
// length: 4
// [[Prototype]]: Array(0)

Object.entries() で処理すると key, val のセット(配列)の配列の形になるので、これならばイテラブルとなるわけです。

改修

ただし、今回は key は使っておらず val のみの使用なので、実は分割代入がいらなかったという。

const imgTags = document.querySelectorAll('img');
for (const [key, val] of Object.entries(imgTags)) { /* 略 */ }

ではなく

const imgTags = document.querySelectorAll('img');
for (const imgTag of imgTags) { /* 略 */ }

これで事足りてしまったというオチ。

ただし、バベる場合は for...of はコードの肥大化につながるのでオススメされない。

実際、分割代入しないのであればわざわざ for...of を使用するまでもないのでは、ということで手を加えることに。

const imgTags = document.querySelectorAll('img');
Object.values(imgTags).map((imgTag) => { /* 略 */ });

結局 Object.values() は使ったものの、 Array.prototype.map() で処理できる。 forEach は遅いとどこかで見た気がするのでなるべく使わずに。

ただ、あまり考えなくても良いかもしれません。

参考

HTMLCollection, NodeList

for...of

map

forEach


Written by Circle
A mound built by the accumulation of hyperlinks are like Kowloon.