`for...of`语句在可迭代对象（包括 `Array`，`Map`，`Set`，`String`，`TypedArray`，arguments 对象等等）上创建一个迭代循环，调用自定义迭代钩子，并为每个不同属性的值执行语句

The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.

## 语法

    for (variable of iterable) {
        //statements
    }

`variable`
  在每次迭代中，将不同属性的值分配给变量。
`iterable`
  被迭代枚举其属性的对象。

## 示例

### 迭代`Array`

    let iterable = [10, 20, 30];

    for (let value of iterable) {
        value += 1;
        console.log(value);
    }
    // 11
    // 21
    // 31

如果你不想修改语句块中的变量 , 也可以使用`const`代替`let`。

    let iterable = [10, 20, 30];

    for (const value of iterable) {
      console.log(value);
    }
    // 10
    // 20
    // 30

### 迭代`String`

    let iterable = "boo";

    for (let value of iterable) {
      console.log(value);
    }
    // "b"
    // "o"
    // "o"

### 迭代 `TypedArray`

    let iterable = new Uint8Array([0x00, 0xff]);

    for (let value of iterable) {
      console.log(value);
    }
    // 0
    // 255

### 迭代`Map`

    let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);

    for (let entry of iterable) {
      console.log(entry);
    }
    // ["a", 1]
    // ["b", 2]
    // ["c", 3]

    for (let [key, value] of iterable) {
      console.log(value);
    }
    // 1
    // 2
    // 3

### 迭代 `Set`

    let iterable = new Set([1, 1, 2, 2, 3, 3]);

    for (let value of iterable) {
      console.log(value);
    }
    // 1
    // 2
    // 3

### 迭代 `arguments` 对象

    (function() {
      for (let argument of arguments) {
        console.log(argument);
      }
    })(1, 2, 3);

    // 1
    // 2
    // 3

### 迭代 DOM 集合

迭代 DOM 元素集合，比如一个`NodeList`对象：下面的例子演示给每一个 article 标签内的 p 标签添加一个 "`read`" 类。

    //注意：这只能在实现了NodeList.prototype[Symbol.iterator]的平台上运行
    let articleParagraphs = document.querySelectorAll("article > p");

    for (let paragraph of articleParagraphs) {
      paragraph.classList.add("read");
    }

### 关闭迭代器

对于`for...of`的循环，可以由`break`, `throw continue` 或`return`终止。在这些情况下，迭代器关闭。

    function* foo(){
      yield 1;
      yield 2;
      yield 3;
    };

    for (let o of foo()) {
      console.log(o);
      break; // closes iterator, triggers return
    }

### 迭代生成器

你还可以迭代一个生成器：

    function* fibonacci() { // 一个生成器函数
        let [prev, curr] = [0, 1];
        for (;;) { // while (true) {
            [prev, curr] = [curr, prev + curr];
            yield curr;
        }
    }

    for (let n of fibonacci()) {
         console.log(n);
        // 当n大于1000时跳出循环
        if (n >= 1000)
            break;
    }

#### 不要重用生成器

生成器不应该重用，即使`for...of`循环的提前终止，例如通过`break`关键字。在退出循环后，生成器关闭，并尝试再次迭代，不会产生任何进一步的结果。

    var gen = (function *(){
        yield 1;
        yield 2;
        yield 3;
    })();
    for (let o of gen) {
        console.log(o);
        break;//关闭生成器
    }

    //生成器不应该重用，以下没有意义！
    for (let o of gen) {
        console.log(o);
    }

### 迭代其他可迭代对象

你还可以迭代显式实现可迭代协议的对象：

    var iterable = {
      [Symbol.iterator]() {
        return {
          i: 0,
          next() {
            if (this.i < 3) {
              return { value: this.i++, done: false };
            }
            return { value: undefined, done: true };
          }
        };
      }
    };

    for (var value of iterable) {
      console.log(value);
    }
    // 0
    // 1
    // 2

### `for...of`与`for...in`的区别

无论是`for...in`还是`for...of`语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。

`for...in` 语句以原始插入顺序迭代对象的可枚举属性。

`for...of` 语句遍历可迭代对象定义要迭代的数据。

以下示例显示了与`Array`一起使用时，`for...of`循环和`for...in`循环之间的区别。

    Object.prototype.objCustom = function() {};
    Array.prototype.arrCustom = function() {};

    let iterable = [3, 5, 7];
    iterable.foo = 'hello';

    for (let i in iterable) {
      console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
    }

    for (let i in iterable) {
      if (iterable.hasOwnProperty(i)) {
        console.log(i); // logs 0, 1, 2, "foo"
      }
    }

    for (let i of iterable) {
      console.log(i); // logs 3, 5, 7
    }

    Object.prototype.objCustom = function() {};
    Array.prototype.arrCustom = function() {};

    let iterable = [3, 5, 7];
    iterable.foo = 'hello';

每个对象将继承`objCustom`属性，并且作为`Array`的每个对象将继承`arrCustom`属性，因为将这些属性添加到`Object.prototype`和`Array.prototype`。由于继承和原型链，对象`iterable`继承属性`objCustom`和`arrCustom`。

    for (let i in iterable) {
      console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
    }

此循环仅以原始插入顺序记录`iterable` 对象的可枚举属性。它不记录数组元素 `3`, `5`, `7` 或`hello`，因为这些不是枚举属性。但是它记录了数组索引以及`arrCustom`和`objCustom`。如果你不知道为什么这些属性被迭代，`array iteration and for...in`中有更多解释。

    for (let i in iterable) {
      if (iterable.hasOwnProperty(i)) {
        console.log(i); // logs 0, 1, 2, "foo"
      }
    }

这个循环类似于第一个，但是它使用`hasOwnProperty()` 来检查，如果找到的枚举属性是对象自己的（不是继承的）。如果是，该属性被记录。记录的属性是`0`, `1`, `2`和`foo`，因为它们是自身的属性（不是继承的）。属性`arrCustom`和`objCustom`不会被记录，因为它们是继承的。

    for (let i of iterable) {
      console.log(i); // logs 3, 5, 7
    }

该循环迭代并记录`iterable`作为可迭代对象定义的迭代值，这些是数组元素 `3`, `5`, `7`，而不是任何对象的属性。

## 规范

Specification | Status | Comment
--- | --- | ---
ECMAScript 2015 (6th Edition, ECMA-262) for...of statement | Standard | Initial definition.
ECMAScript Latest Draft (ECMA-262) for...of statement | Draft |

## 浏览器兼容

The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.

Update compatibility data on GitHub

| Desktop | Mobile | Server
| Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | Android webview | Chrome for Android | Edge Mobile | Firefox for Android | Opera for Android | Safari on iOS | Samsung Internet | Node.js
`for...of` | Chrome Full support 38 | Edge Full support 12 | Firefox Full support 13 Notes Full support 13 Notes Notes Prior to Firefox 51, using the `for...of` loop construct with the `const` keyword threw a `SyntaxError` ("missing = in const declaration"). | IE No support No | Opera Full support 25 | Safari Full support 8 | WebView Android Full support 38 | Chrome Android Full support Yes | Edge Mobile Full support 12 | Firefox Android Full support 14 Notes Full support 14 Notes Notes Prior to Firefox 51, using the `for...of` loop construct with the `const` keyword threw a `SyntaxError` ("missing = in const declaration"). | Opera Android Full support 25 | Safari iOS Full support 8 | Samsung Internet Android Full support Yes | nodejs Full support Yes
async iterators | Chrome Full support 63 | Edge ? | Firefox Full support 57 | IE No support No | Opera Full support 50 | Safari ? | WebView Android Full support 63 | Chrome Android Full support 63 | Edge Mobile ? | Firefox Android Full support 57 | Opera Android Full support 50 | Safari iOS ? | Samsung Internet Android ? | nodejs ?
Closing iterators | Chrome Full support 51 | Edge Full support Yes | Firefox Full support 53 | IE No support No | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Edge Mobile Full support Yes | Firefox Android Full support 53 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes | nodejs Full support Yes

### Legend

Full support
  Full support
No support
  No support
Compatibility unknown
  Compatibility unknown
See implementation notes.
  See implementation notes.

## 相关链接

- `Array.prototype.forEach()`
- `Map.prototype.forEach()`