在 ECMAScript 2020 (ES11) 中,for...in 循环的行为有了一些变化,主要是为了解决一些常见的问题。在本文中,我们将探讨这些变化以及如何解决相关的问题。
问题
在以前的版本中,for...in 循环可以用来遍历对象的属性。例如,以下代码可以打印出对象 obj 的所有属性名和属性值:
const obj = { a: 1, b: 2, c: 3 }; for (const prop in obj) { console.log(`${prop}: ${obj[prop]}`); }
然而,问题在于 for...in 循环不仅遍历对象自身的属性,还会遍历对象原型链上的属性。这可能会导致一些意想不到的行为。
例如,如果我们定义了一个名为 Object.prototype.foo 的属性,那么这个属性将会被 for...in 循环遍历到,即使它是在对象原型链上的属性:
Object.prototype.foo = 'bar'; const obj = { a: 1, b: 2, c: 3 }; for (const prop in obj) { console.log(`${prop}: ${obj[prop]}`); }
这段代码将会打印出以下内容:
a: 1 b: 2 c: 3 foo: bar
这可能会导致一些意想不到的行为,特别是在处理第三方库或框架时。因此,为了避免这种问题,ES11 中对 for...in 循环进行了一些限制。
限制
在 ES11 中,for...in 循环只会遍历对象自身的可枚举属性,而不会遍历对象原型链上的属性。这可以通过以下代码进行演示:
Object.prototype.foo = 'bar'; const obj = { a: 1, b: 2, c: 3 }; for (const prop in obj) { console.log(`${prop}: ${obj[prop]}`); }
在 ES11 中,这段代码将会打印出以下内容:
a: 1 b: 2 c: 3
即使我们在对象原型链上定义了一个属性,它也不会被遍历到。
解决方法
如果您需要遍历对象的所有属性,包括对象原型链上的属性,可以使用 Object.getOwnPropertyNames() 方法。这个方法返回一个数组,包含对象自身的所有属性名称,包括不可枚举属性和 Symbol 类型的属性。您可以使用以下代码进行演示:
Object.prototype.foo = 'bar'; const obj = { a: 1, b: 2, c: 3 }; for (const prop of Object.getOwnPropertyNames(obj)) { console.log(`${prop}: ${obj[prop]}`); }
这段代码将会打印出以下内容:
a: 1 b: 2 c: 3
同时,您也可以使用 Object.getOwnPropertySymbols() 方法来获取对象的 Symbol 类型的属性。以下是示例代码:
// javascriptcn.com code example const sym = Symbol('sym'); const obj = { a: 1, b: 2, c: 3, [sym]: 'symbol' }; for (const prop of Object.getOwnPropertyNames(obj)) { console.log(`${prop}: ${obj[prop]}`); } for (const sym of Object.getOwnPropertySymbols(obj)) { console.log(`${sym.toString()}: ${obj[sym]}`); }
这段代码将会打印出以下内容:
a: 1 b: 2 c: 3 Symbol(sym): symbol
结论
在 ECMAScript 2020 (ES11) 中,for...in 循环的行为有了一些变化,主要是为了解决一些常见的问题。现在,for...in 循环只会遍历对象自身的可枚举属性,而不会遍历对象原型链上的属性。如果您需要遍历对象的所有属性,可以使用 Object.getOwnPropertyNames() 和 Object.getOwnPropertySymbols() 方法。这些变化可以帮助我们更好地处理对象的属性,避免一些意想不到的行为。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/673c370a7088281697c6c4e0