ECMAScript 2015的几个补充，并不是新的内置实现或语法，而是协议。这些协议可以被任何遵循某些约定的对象来实现。

有两个协议：可迭代协议和迭代器协议。

## 可迭代协议

可迭代协议允许 JavaScript 对象去定义或定制它们的迭代行为, 例如（定义）在一个 `for..of` 结构中什么值可以被循环（得到）。一些内置类型都是内置的可迭代类型并且有默认的迭代行为, 比如 `Array` or `Map`, 另一些类型则不是 (比如`Object`) 。

为了变成可迭代对象， 一个对象必须实现 @@iterator 方法, 意思是这个对象（或者它原型链 prototype chain 上的某个对象）必须有一个名字是 `Symbol``.iterator` 的属性:

属性 | 值
--- | ---
`[Symbol.iterator]` | 返回一个对象的无参函数，被返回对象符合迭代器协议。

当一个对象需要被迭代的时候（比如开始用于一个 `for..of循环中`），它的@@iterator 方法被调用并且无参数，然后返回一个用于在迭代中获得值的迭代器。

## 迭代器协议

该迭代器协议定义了一种标准的方式来产生一个有限或无限序列的值，并且当所有的值都已经被迭代后，就会有一个默认的返回值。

当一个对象只有满足下述条件才会被认为是一个迭代器：
它实现了一个 `next()` 的方法并且拥有以下含义：

属性 | 值
--- | ---
`next` | 返回一个对象的无参函数，被返回对象拥有两个属性： `done` (boolean) true:迭代器已经超过了可迭代次数。这种情况下,value的值可以被省略 如果迭代器可以产生序列中的下一个值，则为 false。这等效于没有指定done这个属性。 `value` - 迭代器返回的任何 JavaScript 值。done 为 true 时可省略。 next 方法必须要返回一一个对象，该对象有两个必要的属性： done和value，如果返回一个非对象值（比如false和undefined) 会展示一个 `TypeError` ("iterator.next() returned a non-object value") 的错误

不可能知道一个特定的对象是否实现了迭代器协议，然而创造一个同时满足迭代器协议和可迭代协议的对象是很 容易的（就像下面的example所示）。这样做允许一个迭代器能被不同希望迭代的语法方式所使用。 因此，很少只实现迭代器协议而不实现可迭代协议。

    var myIterator = {
        next: function() {
            // ...
        },
        [Symbol.iterator]: function() { return this }
    }

一些迭代器是转换自可迭代对象:

    var someArray = [1, 5, 7];
    var someArrayEntries = someArray.entries();

    someArrayEntries.toString();           // "[object Array Iterator]"
    someArrayEntries === someArrayEntries[Symbol.iterator]();    // true

## 使用迭代协议的例子

`String` 是一个内置的可迭代对象:

    var someString = "hi";
    typeof someString[Symbol.iterator];          // "function"

`String` 的默认迭代器会一个接一个返回该字符串的字符：

    var iterator = someString[Symbol.iterator]();
    iterator + "";                               // "[object String Iterator]"

    iterator.next();                             // { value: "h", done: false }
    iterator.next();                             // { value: "i", done: false }
    iterator.next();                             // { value: undefined, done: true }

一些内置的语法结构，比如 spread operator （展开语法：[...val]），内部也使用了同样的迭代协议：

    [...someString]                              // ["h", "i"]

我们可以通过自己的 `@@iterator 方法重新定义迭代行为：`

    var someString = new String("hi");          // need to construct a String object explicitly to avoid auto-boxing

    someString[Symbol.iterator] = function() {
      return { // this is the iterator object, returning a single element, the string "bye"
        next: function() {
          if (this._first) {
            this._first = false;
            return { value: "bye", done: false };
          } else {
            return { done: true };
          }
        },
        _first: true
      };
    };

注意重新定义`@@iterator` 方法是如何影响内置语法结构的行为的，它使用数据对象相同的迭代协议:

    [...someString];                              // ["bye"]
    someString + "";                              // "hi"

## 可迭代对象示例

### 内置可迭代对象

`String`, `Array`, `TypedArray`, `Map` and `Set` 是所有内置可迭代对象， 因为它们的原型对象都有一个 `@@``iterator` 方法.

### 自定义可迭代对象

我们可以实现一个自己的可迭代对象，就像这样:

    var myIterable = {};
    myIterable[Symbol.iterator] = function* () {
        yield 1;
        yield 2;
        yield 3;
    };
    [...myIterable]; // [1, 2, 3]

### 接受可迭代对象的内置 API

许多 API 接受可迭代对象（作为参数，译注）, 例如：`Map([iterable])`, `WeakMap([iterable])`, `Set([iterable])` and `WeakSet([iterable])`:

    var myObj = {};
    new Map([[1,"a"],[2,"b"],[3,"c"]]).get(2);               // "b"
    new WeakMap([[{},"a"],[myObj,"b"],[{},"c"]]).get(myObj); // "b"
    new Set([1, 2, 3]).has(3);                               // true
    new Set("123").has("2");                                 // true
    new WeakSet(function*() {
        yield {};
        yield myObj;
        yield {};
    }()).has(myObj);                                         // true

另外还有 `Promise.all(iterable)`, `Promise.race(iterable)` 以及 `Array.from()`.

### 用于可迭代对象的语法

一些语句和表达式是预料会用于可迭代对象，比如 `for-of` 循环，spread operator, `yield*` 和 destructuring assignment。

    for(let value of ["a", "b", "c"]){
        console.log(value);
    }
    // "a"
    // "b"
    // "c"

    [..."abc"]; // ["a", "b", "c"]

    function* gen(){
      yield* ["a", "b", "c"];
    }

    gen().next(); // { value:"a", done:false }

    [a, b, c] = new Set(["a", "b", "c"]);
    a // "a"

### Non-well-formed (非-良好-格式化的)可迭代对象

如果一个可迭代对象的 `@@iterator 方法不是返回一个迭代器对象，那么它就是一个` non-well-formed 可迭代对象 。使用它可能会发生如下的运行时异常或者 buggy 行为:

    var nonWellFormedIterable = {}
    nonWellFormedIterable[Symbol.iterator] = () => 1
    [...nonWellFormedIterable] // TypeError: [] is not a function

## 迭代器示例

### 简单迭代器

    function makeIterator(array){
        var nextIndex = 0;

        return {
           next: function(){
               return nextIndex < array.length ?
                   {value: array[nextIndex++], done: false} :
                   {done: true};
           }
        };
    }

    var it = makeIterator(['yo', 'ya']);

    console.log(it.next().value); // 'yo'
    console.log(it.next().value); // 'ya'
    console.log(it.next().done);  // true

### 无穷迭代器

    function idMaker(){
        var index = 0;

        return {
           next: function(){
               return {value: index++, done: false};
           }
        };
    }

    var it = idMaker();

    console.log(it.next().value); // '0'
    console.log(it.next().value); // '1'
    console.log(it.next().value); // '2'
    // ...

### 生成器式的迭代器

    function* makeSimpleGenerator(array){
        var nextIndex = 0;

        while(nextIndex < array.length){
            yield array[nextIndex++];
        }
    }

    var gen = makeSimpleGenerator(['yo', 'ya']);

    console.log(gen.next().value); // 'yo'
    console.log(gen.next().value); // 'ya'
    console.log(gen.next().done);  // true

    function* idMaker(){
        var index = 0;
        while(true)
            yield index++;
    }

    var gen = idMaker();

    console.log(gen.next().value); // '0'
    console.log(gen.next().value); // '1'
    console.log(gen.next().value); // '2'
    // ...

## 生成器对象到底是一个迭代器还是一个可迭代对象?

生成器对象 既是迭代器也是可迭代对象:

就像前面说说的，一个良好的迭代即实现了迭代器协议，又实现了可迭代协议，方式就是可迭代协议返回的是自身

    var aGeneratorObject = function*(){
        yield 1;
        yield 2;
        yield 3;
    }();
    typeof aGeneratorObject.next;
    // "function", because it has a next method, so it's an iterator
    typeof aGeneratorObject[Symbol.iterator];
    // "function", because it has an @@iterator method, so it's an iterable
    aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
    // true, because its @@iterator method return its self (an iterator), so it's an well-formed iterable
    [...aGeneratorObject];
    // [1, 2, 3]

## 浏览器兼容性

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!

- Desktop
- Mobile

特性 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit)
--- | --- | --- | --- | --- | ---
基本支持 | 39.0 | 27.0 (27.0) | 未实现 | 26 | 未实现
`IteratorResult` object instead of throwing | (Yes) | 29.0 (29.0) | 未实现 | (Yes) | 未实现

特性 | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android
--- | --- | --- | --- | --- | --- | --- | ---
基本支持 | 未实现 | (Yes) | 27.0 (27.0) | 未实现 | 未实现 | 未实现 | 39.0
`IteratorResult` object instead of throwing | 未实现 | ? | 29.0 (29.0) | 未实现 | 未实现 | 未实现 | (Yes)

## Firefox-specific 批注

### `IteratorResult` 用对象返回代替错误抛出

从Gecko 29 (Firefox 29 / Thunderbird 29 / SeaMonkey 2.26)开始, 构造器不再抛出 `TypeError` "generator has already finished". 取而代之的是它返回一个`IteratorResult`对象类似于 `{ value: undefined, done: true }` (bug 958951).

### `Iterator` property and `@@iterator` symbol

From Gecko 17 (Firefox 17 / Thunderbird 17 / SeaMonkey 2.14) to Gecko 26 (Firefox 26 / Thunderbird 26 / SeaMonkey 2.23 / Firefox OS 1.2) the `iterator` property was used (bug 907077), and from Gecko 27 to Gecko 35 the `"@@iterator"` placeholder was used. In Gecko 36 (Firefox 36 / Thunderbird 36 / SeaMonkey 2.33), the `@@iterator` symbol got implemented (bug 918828).

## 规范

规范 | 状态 | 备注
--- | --- | ---
ECMAScript 2015 (6th Edition, ECMA-262) Iteration | Standard | Initial definition.
ECMAScript Latest Draft (ECMA-262) Iteration | Draft | ES7(ES2016/ES2017)

## 参考

- 更多有关 ES2015 生成器的信息，请参考 the function*() documentation.