JavaScript: forEach、mapでもコールバック関数の第2引数から添字を取れるのでforを使う必要はない

commits2 min read読了の目安(約2100字

for-of / forEach / map でも添字は取れます

https://qiita.com/tetsuya-zama/items/11e19b9da4892eb365c4

この記事のブコメ等で「for-of では添字を取れないので添字が欲しかったら for を使う」と解釈できるものを複数発見しました。Twitter 検索からも似たような認識を持っている方がいらっしゃるようです。これは勘違いです。for-of / forEach / map でも添字は取れるので、添字がほしいだけなら素の for を使う必要はありません

forEach map の第 2 引数は添字

forEach map の場合は非常に簡単です。実はこれらのメソッドが受け取るコールバック関数は、第 1 引数が要素、第 2 引数が添字、第 3 引数がもとの配列、という構成になっているので、普通に第 2 引数を取れば OK です。

const arr = [1, 2, 3, 4, 5];

arr.forEach((value, index) => {
  console.log(`${index}: ${value}`);
});

前の要素と等しいか判定し出力してみましょう。

const arr = [1, 2, 3, 3, 4, 5];

arr.forEach((value, index) => {
  console.log(value === arr[index - 1]);
});

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

entries を使えば for-of でも添字が取得できる

for-of の場合は forEach よりちょっと難しいです。of arrof arr.entries() に置き換え、変数を分割代入にします。forEach の引数と順番が逆なので注意してください。

const arr = [1, 2, 3, 4, 5];

for (const [index, value] of arr.entries()) {
  console.log(`${index}: ${value}`);
}

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/entries

array.entries()[添字, 要素] という値を生成するイテレータオブジェクトを返す関数です。イテレータは配列みたいに連続した値が入っていて、配列みたいに for ofof の右側に置くことで各要素に繰り返し処理を行えます。

ちなみによく似た Object.entries() という関数もあり、for (const [index, value] of Object.entries(arr)) という使い方もできるのですが、これだと [index] が数値でなく文字列になってしまっているので扱いづらいです。これは、配列の添字 0, 1, ... が実は数値でなく文字列 '0', '1', ... で保持されているからです。arr[0] という添字アクセスも型変換で arr['0'] に置き換えられています。お手元の開発者ツールとかでぜひお試しください。


for-offorEach map でも添字を使えるので、添字を取得したいだけなら素の for を使う必要はない、ということを説明しました。

行いたい処理が複雑になるとどうしても for (let i = 0; ...) という素朴な for 文を書かなければいけない場面は存在します。それは仕方ないことですが、今ではありません。for で妥協する前に MDN で Array のメソッドの項目 で適切な関数を探したり、なかったら自分で作ったりする、そういう人が増えたらいいなあと思っています。