`for...in`语句以任意顺序遍历一个对象的可枚举属性。对于每个不同的属性，语句都会被执行。

## 语法

    for (variable in object) {...}

`variable`
  在每次迭代时，将不同的属性名分配给变量。

`object`
  被迭代枚举其属性的对象。

## 描述

`for...in` 循环只遍历可枚举属性。像 `Array`和 `Object`使用内置构造函数所创建的对象都会继承自`Object.prototype`和`String.prototype`的不可枚举属性，例如 `String` 的 `indexOf()` 方法或 `Object`的`toString()`方法。循环将遍历对象本身的所有可枚举属性，以及对象从其构造函数原型中继承的属性（更接近原型链中对象的属性覆盖原型属性）。

#### 删除，添加或者修改属性

`for...in` 循环以任意序迭代一个对象的属性（请参阅`delete`运算符，了解为什么不能依赖于迭代的表面有序性，至少在跨浏览器设置中）。如果一个属性在一次迭代中被修改，在稍后被访问，其在循环中的值是其在稍后时间的值。一个在被访问之前已经被删除的属性将不会在之后被访问。在迭代进行时被添加到对象的属性，可能在之后的迭代被访问，也可能被忽略。

通常，在迭代过程中最好不要在对象上进行添加、修改或者删除属性的操作，除非是对当前正在被访问的属性。这里并不保证是否一个被添加的属性在迭代过程中会被访问到，不保证一个修改后的属性（除非是正在被访问的）会在修改前或者修改后被访问，不保证一个被删除的属性将会在它被删除之前被访问。

### 数组迭代和 `for...in`

提示：`for...in`不应该用于迭代一个 `Array`，其中索引顺序很重要。

数组索引只是具有整数名称的枚举属性，并且与通用对象属性相同。不能保证`for ... in`将以任何特定的顺序返回索引。`for ... in`循环语句将返回所有可枚举属性，包括非整数类型的名称和继承的那些。

因为迭代的顺序是依赖于执行环境的，所以数组遍历不一定按次序访问元素。因此当迭代访问顺序很重要的数组时，最好用整数索引去进行`for`循环（或者使用 `Array.prototype.forEach()` 或 `for...of` 循环）。

### 仅迭代自身的属性

如果你只要考虑对象本身的属性，而不是它的原型，那么使用 `getOwnPropertyNames()` 或执行 `hasOwnProperty()` 来确定某属性是否是对象本身的属性（也能使用`propertyIsEnumerable`）。或者，如果你知道不会有任何外部代码干扰，您可以使用检查方法扩展内置原型。

## 示例

下面的函数接受一个对象作为参数。被调用时迭代传入对象的所有可枚举属性然后返回一个所有属性名和其对应值的字符串。

    var obj = {a:1, b:2, c:3};

    for (var prop in obj) {
      console.log("obj." + prop + " = " + obj[prop]);
    }

    // Output:
    // "obj.a = 1"
    // "obj.b = 2"
    // "obj.c = 3"

下面的函数说明了`hasOwnProperty()`的用法：继承的属性不显示。

    var triangle = {a: 1, b: 2, c: 3};

    function ColoredTriangle() {
      this.color = 'red';
    }

    ColoredTriangle.prototype = triangle;

    var obj = new ColoredTriangle();

    for (var prop in obj) {
      if (obj.hasOwnProperty(prop)) {
        console.log(`obj.${prop} = ${obj[prop]}`);
      }
    }

    // Output:
    // "obj.color = red"

## 规范

Specification | Status | Comment
--- | --- | ---
ECMAScript Latest Draft (ECMA-262) for...in statement | Draft |
ECMAScript 2015 (6th Edition, ECMA-262) for...in statement | Standard |
ECMAScript 5.1 (ECMA-262) for...in statement | Standard |
ECMAScript 3rd Edition (ECMA-262) for...in statement | Standard |
ECMAScript 1st Edition (ECMA-262) for...in statement | Standard | Initial definition.

## 浏览器兼容

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...in` | Chrome Full support Yes | Edge Full support Yes | Firefox Full support 1 | IE Full support 6 | 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 4 | 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

## 兼容性：初始化函数表达式

在 SpiderMonkey 40 (Firefox 40 / Thunderbird 40 / SeaMonkey 2.37) 版本之前，可以在使用一个初始化表达式（`i=0`）在一个`for...in`循环中：

    var obj = {a: 1, b: 2, c: 3};
    for (var i = 0 in obj) {
      console.log(obj[i]);
    }
    // 1
    // 2
    // 3

这个非标准行为现在在版本40及更高版本中被忽略，并将在严格模式（bug 748550 和 bug 1164741）中呈现`SyntaxError`（"for-in loop head declarations may not have initializers"）错误。

像其他引擎 V8(Chrome)，Chakra (IE/Edge)， JSC (WebKit/Safari) 正在研究去除这种不标准的行为。

## 相关链接

- `for...of` 一个类似的迭代属性值的语句
- `for each in` 一个类似的但是迭代的是对象的属性的值而不是其属性名字的语句（过时的）
- `for`
- 迭代器和构造器（uses the `for...in` syntax）
- 属性的可枚举性和所有权
- `Object.getOwnPropertyNames()`
- `Object.prototype.hasOwnProperty()`
- `Array.prototype.forEach()`