---
type: reference
language: javascript
slug: iterator/iterable
title: "反復可能とイテレータ — for...of で回せるものの正体"
title_tag: "JavaScript の反復可能オブジェクト — Symbol.iterator と generator"
summary: >
  for...of とスプレッドが使えるかどうかは Symbol.iterator を持つかで決まります。
  自分で作る方法、ジェネレータ、1度きりしか回せないこと、無限の列を扱う形まで実行して確かめます。
description: >
  オブジェクトが for...of で回せないのは Symbol.iterator が無いからです。自分で持たせる方法、
  ジェネレータで短く書く形、1度回すと空になる落とし穴まで実行して確かめられます。
status: published
difficulty: 3
minutes: 10

versions:
  verified: "Node 22.22.3"
  since: "ES2015"
  deprecated: null
  removed: null

sources:
  - title: "Iteration — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-iteration"
  - title: "Generator Function Definitions — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-generator-function-definitions"
  - title: "反復処理プロトコル — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols"

terms: [反復可能, イテレータ, ジェネレータ, 遅延評価]

links:
  related:
    - javascript/errors/is-not-iterable
    - javascript/reference/operator/spread
    - javascript/reference/collection/map-set
    - javascript/learn/array/loop

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

`for...of` とスプレッドが使えるかどうかは、**たった1つの決まりで決まります。**

```js run
for (const value of [[1], 'ab', new Set([1]), new Map([['a', 1]])]) {
  console.log(typeof value[Symbol.iterator]);
}

console.log(typeof ({})[Symbol.iterator]);
```
```output
function
function
function
function
undefined
```

**`Symbol.iterator` という名前の関数を持っていれば回せます。**
素のオブジェクトはこれを持っていません。だから落ちます。

```js bad
for (const value of { a: 1 }) {
  console.log(value);
}
```
```output
TypeError: {(intermediate value)} is not iterable
```

| 回せるもの | 回せないもの |
|---|---|
| 配列 / 文字列 / `Set` / `Map` | **素のオブジェクト** |
| `arguments` | `{ length: 3 }` のような形だけ似たもの |
| ジェネレータ | 数値・真偽値 |

素のオブジェクトを回すなら、いったん配列にします。

```js run
for (const [key, value] of Object.entries({ a: 1, b: 2 })) {
  console.log(key, value);
}
```
```output
a 1
b 2
```

→ [Object.keys() / values() / entries()](/ja/javascript/reference/object/keys/)

## 中身は「次を返す関数」だけ

`Symbol.iterator` を呼ぶと[type:イテレータ]が返り、それに `next()` を聞きます。

```js run
const iterator = [10, 20][Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
```
```output
{ value: 10, done: false }
{ value: 20, done: false }
{ value: undefined, done: true }
```

**`done` が `true` になるまで呼び続ける。** `for...of` がやっているのはこれだけです。

## 自分で作る

`Symbol.iterator` を持たせれば、素のオブジェクトでも回せます。

```js run
const range = {
  from: 1,
  to: 3,
  *[Symbol.iterator]() {
    for (let i = this.from; i <= this.to; i++) {
      yield i;
    }
  },
};

console.log([...range]);
console.log(Array.from(range));
```
```output
[ 1, 2, 3 ]
[ 1, 2, 3 ]
```

`function*` と `yield` で書くと、`next()` を自分で用意しなくて済みます。
**これを[type:ジェネレータ]と呼びます。**

## ジェネレータ

```js run
function* gen() {
  yield 1;
  yield 2;
  return 99;
}

const g = gen();

console.log(g.next(), g.next(), g.next(), g.next());
console.log([...gen()]);
```
```output
{ value: 1, done: false } { value: 2, done: false } { value: 99, done: true } { value: undefined, done: true }
[ 1, 2 ]
```

- `yield` で[key:止まって値を返し]、次に呼ばれたら続きから動く
- `return` した値は `done: true` と一緒に来る
- **`for...of` とスプレッドは `return` の値を拾いません**（`[1, 2]` だけ）

[bad:`return` に意味のある値を入れないでください。] 多くの書き方で消えます。

## 1度回すと空になる

**ここがいちばん事故になります。**

```js bad
function* gen() {
  yield 1;
  yield 2;
}

const g = gen();

console.log([...g]);
console.log([...g]);
```
```output
[ 1, 2 ]
[]
```

配列は何度でも回せますが、**イテレータは使い切りです。**

```js run
const array = [1, 2];

console.log([...array], [...array]);
```
```output
[ 1, 2 ] [ 1, 2 ]
```

2回使うなら、**先に配列にしてください。**

```js run
function* gen() {
  yield 1;
  yield 2;
}

const values = [...gen()];

console.log(values, values);
```
```output
[ 1, 2 ] [ 1, 2 ]
```

## 終わらない列も書ける

`return` するまで作られないので、**無限に続く列を書いても止まりません。**

```js run
function* naturals() {
  let n = 1;
  while (true) {
    yield n++;
  }
}

function* take(iterable, count) {
  let i = 0;
  for (const value of iterable) {
    if (i++ >= count) return;
    yield value;
  }
}

console.log([...take(naturals(), 5)]);
```
```output
[ 1, 2, 3, 4, 5 ]
```

必要になったときにだけ計算されます。これを[type:遅延評価]と呼びます。

`[...naturals()]` と書くと[bad:止まりません]。必ず打ち切りを挟んでください。

## 途中で抜けたときの後始末

```js run
function* gen() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } finally {
    console.log('後始末');
  }
}

for (const n of gen()) {
  console.log(n);
  if (n === 2) break;
}
```
```output
1
2
後始末
```

`break` で抜けても、**`finally` は動きます。**
ファイルや接続を閉じる処理を、安心して書けます。
→ [Error と try / catch / finally / throw](/ja/javascript/reference/error/error/)

## どこで効いてくるか

`Symbol.iterator` を持っていれば、**言語のいろいろな場所がそのまま使えます。**

```js run
function* gen() {
  yield 1;
  yield 2;
}

const [first, ...rest] = gen();

console.log(first, rest);
console.log(Math.max(...gen()));
console.log(new Set(gen()));
console.log(Object.fromEntries([['a', 1]]));
```
```output
1 [ 2 ]
2
Set(2) { 1, 2 }
{ a: 1 }
```

`for...of`・スプレッド・分割代入・`Array.from()`・`new Set()`・`new Map()`。
**入口が1つなので、対応する場所が一気に増えます。**

## まとめ

- 回せるかどうかは[key:Symbol.iterator を持つか]だけで決まる
- 素のオブジェクトは持っていない。`Object.entries()` を挟む
- 中身は `next()` が `{ value, done }` を返すだけ
- `function*` と `yield` で短く書ける
- **イテレータは使い切り。** 2回使うなら先に配列にする
- 終わらない列も書ける。ただし[bad:打ち切りを忘れると止まらない]
- `break` で抜けても `finally` は動く
