JavaScriptのイテラブル(Iterable)って何? 初心者でもわかるように詳しく解説するよ

目次

はじめに

おいおい、JavaScriptやってるのにイテラブル知らないなんて、配列ばっかfor文で回して疲れてんの? 笑

まあ、ES6から本格的に入ってきた機能だから、知らなくても生きていけるけど、知ったら世界が変わるよ。for…ofループとかスプレッド演算子とか、めっちゃ便利になるからさ。

まず、イテラブルとは何ぞや?

イティセル/コード専門官

JavaScriptのイテラブル(Iterable)とは、順番に要素を取り出せるオブジェクトのこと。簡単に言うと、「for…ofでループできるやつ」だよ。

  • 配列(Array)
  • 文字列(String)
  • Map
  • Set
  • NodeList(DOMの要素集合)

これらはデフォルトでイテラブル。普通のオブジェクト({})はデフォルトじゃイテラブルじゃないんだよね。なんで? だってオブジェクトはキー順が保証されてない古い仕様だからさ(笑)。

MDNによると、イテラブルはSymbol.iteratorっていう特殊なプロパティを持ってて、それがイテレーターを返す関数になってるオブジェクトだよ。

イテレーター(Iterator)って何?

イテレーター:「はい、次の方〜!」

イティセル/コード専門官

イテラブル(配列とか)が「客が並んでる行列」だとしたら、イテレーターは「窓口の係員」だ。

この係員(イテレーター)は、next() というボタンを押されるたびに、機械的にこう対応する。

  1. 客(値)を一人通す。
  2. 「まだ後ろに誰かいますか?」という旗(フラグ)を振る。

こいつの返事は常にこの 決まり文句(オブジェクト) だけだ。

// next() を呼ぶと...

{ value: '客A', done: false } 
// 「はい、客Aさんどうぞ。あ、まだ後ろ並んでますね(done: false)」

{ value: '客B', done: false }
// 「はい、客Bさんどうぞ。まだいますね(done: false)」

{ value: undefined, done: true }
// 「...え? もう誰もいませんよ? 閉店です(done: true)」
イティセル/コード専門官

ここがポイントだよ

  • value: お目当てのモノ(中身)。
  • done: 「もう終わり? まだある?」 という終了合図。

done: true になったら、何度 next() を呼んでも 「いや、だから無いって! 帰れよ!」{ value: undefined, done: true })と言い続ける。頑固なやつなんだよ。

for…ofループでどう使うの?

イティセル/コード専門官

はい、来ました。イテラブル界の「全自動ベルトコンベア」こと for...of ループ先輩の登場です。

古臭い for (let i = 0; ...) とかいう「手動カウンター」は窓から投げ捨てろ! for...of は、「中身をよこせ、話はそれからだ」という非常に直感的で、かつ強欲なループです。

1. 配列(Array)の場合

「回転寿司の皿を全部食う」イメージです。インデックス(何番目か)なんてどうでもいい。ネタ(値)だけをよこせ。

const arr = ['', '', ''];

// 翻訳:「arr の中から、順番に item という皿に取り出して食う」
for (const item of arr) {
  console.log(item); 
}
出力結果


ポイント: > item はただの変数名です。sushi でも yatsura でも何でもOK。

2. 文字列(String)の場合

文字列を for...of に突っ込むと、「千切り(スライス)」にされます。

// 文字列だって「文字の並び」だろ? バラバラにしてやるよ!
for (const char of 'JavaScript') {
  console.log(char);
}
出力: 
J
a
v
...中略...
t

狂気: > 昔は .split('') とかやって配列にして回してましたが、今はそのまま放り込めばOK。楽すぎて脳が退化しそうです。

3. ここが重要! vs for...in

イティセル/コード専門官

ここテストに出ます。というか、ハマって泣く人が続出します

  • for...of (今回の主役)
    • 「中身(値)」 を持ってくる。
    • 優秀なウェイター。 「ハンバーグお持ちしました」
  • for...in (紛らわしい悪魔)
    • 「キー(インデックスやプロパティ名)」 を持ってくる。
    • 空気読めない客。 「メニューの3番目の項目!」(いや中身言えよ)
const list = ['A', 'B', 'C'];

// for...in の罠(インデックスが返ってくる)
for (const x in list) {
  console.log(x);
}

// for...of の正義(値が返ってくる)
for (const x of list) {
  console.log(x);
}
"0", "1", "2"  // ← は? お前誰?(※しかも文字列で返る)
"A", "B", "C"  // ← これこれ!これが欲しかったの!

for...of は、「順番があるもの(イテラブル)」なら何でも、何も考えずに中身を順番に取り出してくれる、思考停止に最適な最高のマシーンです。

MapやSetも同じノリで回せますが、まずは「配列の中身を全部見たいときは、これ一択」と覚えておけば、明日からドヤ顔でコードが書けます。

Symbol.iteratorのコード例見てみよう

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();

console.log(iterator.next());  // { value: 1, done: false }
console.log(iterator.next());  // { value: 2, done: false }
console.log(iterator.next());  // { value: 3, done: false }
console.log(iterator.next());  // { value: undefined, done: true }

JavaScriptにおいて、配列 [1, 2, 3] はただデータが並んでいるだけの状態です。 しかし、こいつに Symbol.iterator という「召喚魔法」を唱えると、データを一つずつ丁寧(かつ無慈悲)に渡してくれる「専任の担当者(イテレータ)」が現れます。

コードの動きを超訳するとこうなります。

1. 担当者を呼び出す

const arr = [1, 2, 3]; // 客が3人並んでる
const iterator = arr[Symbol.iterator](); // 「おい、案内係! 出てこい!」

ここではまだデータは出てきません。 「案内係(イテレータ)」がシフトに入っただけです。こいつはまだ棒立ちです。

2. 1回目の尋問

console.log(iterator.next());
// 結果: { value: 1, done: false }

あなた:「おい、次!」 案内係:「はい、『1』です。(まだ残業は続くので done: false です)」

3. 2回目の尋問

console.log(iterator.next());
// 結果: { value: 2, done: false }

あなた:「おい、次!」 案内係:「はい、『2』です。(まだ帰れません done: false です)」

4. 3回目の尋問

console.log(iterator.next());
// 結果: { value: 3, done: false }

あなた:「おい、次!」 案内係:「はい、『3』です。(次でラストなんでまだ done: false です)」

5. 最後の無慈悲な宣告

console.log(iterator.next());
// 結果: { value: undefined, done: true }

あなた:「おい、次!」 案内係:「ありません!!!(value: undefined) 閉店です!!! 帰ってください!!!(done: true

イティセル/コード専門官

このコードは、普段は全自動で行われる「データ渡し」を、指差し確認しながらマニュアル操作している状態です。

  • value: 渡されたブツ。
  • done: 「もう店じまいしていいか?」のフラグ。false ならまだ営業中、true ならシャッターが閉まった状態。

普段何気なく使っている for (const x of arr) は、裏でこの「案内係」をこき使い、done: true になるまで next() を連打し続けているブラック企業のような仕組みなわけです。

カスタムイテラブル作ってみよう(実践編)

お前もオリジナル作れるよ。簡単だから試せ。

例: 1から10までの範囲オブジェクト

const range = {
  from: 1,
  to: 10,
  [Symbol.iterator]() {  // これが大事!
    let current = this.from;
    const last = this.to; // ここでthisを捕まえておくと安全
    return {
      next() {
        if (current <= last) {
          return { value: current++, done: false };
        }
        return { done: true };
      }
    };
  }
};

for (const num of range) {
  console.log(num);  // 1から10まで出力
}

無限ループ版とかも作れるけど、for…ofで回したらブラウザ死ぬから気をつけろよ(笑)。

ジェネレーター使えばもっと楽

function* generatorRange() {
  for (let i = 1; i <= 10; i++) {
    yield i;
  }
}

for (const num of generatorRange()) {
  console.log(num);
}

ジェネレーターは自動でイテラブルになるんだぜ。便利すぎ。

イテラブルが使えるところ(リストアップ)

  • for…of ループ
  • スプレッド演算子 […] (配列展開)
  • 配列分解代入 [a, b] = iterable
  • Array.from(iterable)
  • new Map(iterable)
  • new Set(iterable)
  • Promise.all(iterable) とか

非同期イテラブル(Async Iterable)もあるけど、それはまた別話。

まとめ:イテラブル知らないと損だよ

JavaScriptのイテラブルは、データ集合を統一的に扱える神機能。配列以外もfor…ofでサクサクループできるし、カスタム作れば無限の可能性。古いfor文やforEachに頼ってる人は、今日から乗り換えろよ。本当に便利だからな。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ITTIのアバター ITTI 運営長

ITTI運営長 / 元国家公務員ブロガー
国家公務員として5年間従事した後、新たな挑戦のために退職。調べものと学ぶことが止められなくなり、現在は以下の5ブログを運営中:
・ITTI局(メイン)
・DXブログ
・CODEブログ(今ここ!)
・INFRAブログ
・XRブログ
保有資格:ITパスポート
目標資格:情報処理安全確保支援士(学ぶこと多すぎて道のりは遠いですが、毎日コツコツ進めています…泣)

ブログでは公務員時代の実体験と最新技術を掛け合わせて、読者の「わかりにくい」を「わかる!」に変える記事を発信。最終目標は、これらの知識を活かして「ドラえもんのような万能AI」を開発すること(副運営長任命が待ち遠しい!)。
IT・DXに興味ある方、気軽にX(@llEqmDGOYZ4258)でDMください。一緒に学びましょう!

公務員のキャラがコードを解説!?パロディのブログ『ITTI CODE』、発信中!

コメント

コメントする

目次