JS 的 for-in: 只遍历对象的自有属性还是原型链的属性?
2023-10-14 13:17:19
在 JavaScript 中,我们经常会使用 for-in 循环来遍历对象。但您知道 for-in 究竟是怎样工作的吗?它是否会遍历原型链上的属性?
一、实验
让我们通过一个简单的实验来验证 for-in 的行为。我们将创建一个对象,并在其中添加一个属性和一个方法。然后,我们将使用 for-in 循环来遍历该对象。
const object = {
name: 'John Doe',
greet() {
console.log('Hello, world!');
},
};
for (const key in object) {
console.log(key);
}
输出结果:
name
正如您所见,for-in 只遍历了对象的自有属性 name
,而没有遍历方法 greet()
。这表明 for-in 只遍历对象的自有属性,而不会遍历原型链上的属性。
二、原理
JavaScript 中,对象是通过原型链来实现继承的。每个对象都有一个 __proto__
属性,指向其原型对象。原型对象也有自己的 __proto__
属性,以此类推。这种链条一直延伸到 Object.prototype
,它是所有对象的最终原型对象。
当我们使用 for-in 循环遍历对象时,它只遍历对象的自有属性。这是因为 for-in 循环是通过访问对象的 [[OwnPropertyNames]]
内部槽来获取属性名的。[[OwnPropertyNames]]
内部槽只包含对象的自有属性名,不包含原型链上的属性名。
三、如何遍历原型链上的属性?
既然 for-in 无法遍历原型链上的属性,那么我们该如何遍历原型链上的属性呢?我们可以使用 Object.getPrototypeOf()
方法来获取对象的原型对象,然后使用 for-in 循环来遍历原型对象。以此类推,我们可以遍历整个原型链上的属性。
let object = {
name: 'John Doe',
};
while (object = Object.getPrototypeOf(object)) {
for (const key in object) {
console.log(key);
}
}
输出结果:
constructor
hasOwnProperty
isPrototypeOf
propertyIsEnumerable
toLocaleString
toString
valueOf
这表明我们成功地遍历了原型链上的属性。
四、结论
JavaScript 中的 for-in 循环只遍历对象的自有属性,而不会遍历原型链上的属性。如果我们需要遍历原型链上的属性,可以使用 Object.getPrototypeOf()
方法来获取对象的原型对象,然后使用 for-in 循环来遍历原型对象。以此类推,我们可以遍历整个原型链上的属性。