for...in 用来遍历(迭代)对象自身或继承的非 Symbol 类型的可枚举的属性。
var str = "";
var obj = {a: 1, b: 2, c: 3};
for (var property in obj) {
str += obj[property];
}
console.log(str); // expected output: "123"
语法
for (variable in object) {...}
// variable: 在每次迭代时将不同的属性名分配给变量。
// object: 迭代非 Symbol 类型的可枚举的属性对象。
描述
for...in
循环只遍历可枚举的非 Symbol 类型的属性。像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())。或者,如果你知道不会有任何外部代码干扰,您可以使用检查方法扩展内置原型。
实例
下面的for ... in循环遍历所有对象可枚举非 Symbol 类型的属性,并记录属性名称及其值的字符串。
var obj = {a: 1, b: 2, c: 3};
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
// expected 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 property in obj) {
if (obj.hasOwnProperty(property)) {
console.log(`obj.${property} = ${obj[property]}`);
}
}
// expected output:
// obj.color = red