说我有一个像person
这样的对象
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}
我创建了一个新对象john
并将其原型设置为person
var john = {
firstname: 'John',
lastname: 'Doe'
}
john.__proto__ = person;
如果我console.log
john
,我会看到一个像这样的树结构
我们在getFullName
下看到__proto__
。现在出现了惊喜
for (var prop in john) {
console.log(prop)
}
返回
即使getFullName
深一层,但循环能够找到它。
现在,将其与
进行比较var obj = {a: 1, b: {c:2, d: 3 }}
for (var prop in obj) {console.log(prop)}
的行为符合我的预期,即循环未自动找到c
和d
那么在前一种情况下,循环是如何在树中更深入地挖掘嵌入属性而在后者中却没有呢?
答案 0 :(得分:4)
for..in
循环将迭代所有自己的可枚举属性,以及继承的可枚举属性。这就是你在循环中看到getFullName
的原因。
但在第二种情况下,它仅列出obj
的属性,实际上只有a
和b
属性c
和d
属性对象b
)。
This是语言规范的相应部分,适用于for..in
,它使用内部[[Enumerate]]
广告位。
内部[[Enumerate]]
槽将用于枚举传递给它的对象,该对象提供对象的可枚举属性。引用该部分,
枚举目标对象的属性包括枚举其原型的属性和原型的原型,等等,递归;
由于for..in
递归地上升原型链,我们能够看到原型中定义的对象,在本例中为getFullName
。
如果您不希望在迭代期间显示getFullName
,那么您可以将其定义为不可枚举,例如
var person = {
firstname: 'Default',
lastname: 'Default'
};
Object.defineProperty(person, 'getFullName', {
value: function() {
return this.firstname + ' ' + this.lastname;
},
enumerable: false
});
现在,当您打印密钥时,getFullName
将不会显示,因为它不再是可枚举的。
注意:应避免使用__proto__
,因为它不是ECMAScript规范的一部分。相反,您应该使用Object.setPrototypeOf
。