for...in

for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。

语法

for (variable in object)
  statement
variable
在每次迭代时,variable会被赋值为不同的属性名。
object
非Symbol类型的可枚举属性被迭代的对象。

描述

for...in 循环只遍历可枚举属性(包括它的原型链上的可枚举属性)。像 ArrayObject使用内置构造函数所创建的对象都会继承自Object.prototypeString.prototype的不可枚举属性,例如 toString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。

删除,添加或者修改属性

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

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

数组迭代和 for...in

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

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

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

仅迭代自身的属性

如果你只要考虑对象本身的属性,而不是它的原型,那么使用 propertyIsEnumerable)。或者,如果你知道不会有任何外部代码干扰,您可以使用检查方法扩展内置原型。

为什么用for ... in?

for ... in是为遍历对象属性而构建的,不建议与数组一起使用,数组可以用Array.prototype.forEach()for ... of,那么for ... in的到底有什么用呢?

它最常用的地方应该是用于调试,可以更方便的去检查对象属性(通过输出到控制台或其他方式)。尽管对于处理存储数据,数组更实用些,但是你在处理有key-value数据(比如属性用作“键”),需要检查其中的任何键是否为某值的情况时,还是推荐用for ... in

示例

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

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.

浏览器兼容

Update compatibility data on GitHub
Desktop Mobile Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet Node.js
for...in Chrome Full support 49 Edge Full support 12 Firefox Full support 1 IE Full support 6 Opera Full support 36 Safari Full support Yes WebView Android Full support 49 Chrome Android Full support 49 Firefox Android Full support 4 Opera Android Full support 36 Safari iOS Full support Yes Samsung Internet Android Full support 5.0 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) 正在研究去除这种不标准的行为。

相关链接