循环索引如何提升原型链?

时间:2016-01-16 06:30:28

标签: javascript prototype

说我有一个像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,我会看到一个像这样的树结构

enter image description here

我们在getFullName下看到__proto__。现在出现了惊喜

for (var prop in john) {
  console.log(prop)
}

返回

enter image description here

即使getFullName深一层,但循环能够找到它。

现在,将其与

进行比较
var obj = {a: 1, b: {c:2, d: 3 }}
for (var prop in obj) {console.log(prop)}

的行为符合我的预期,即循环未自动找到cd

enter image description here

那么在前一种情况下,循环是如何在树中更深入地挖掘嵌入属性而在后者中却没有呢?

1 个答案:

答案 0 :(得分:4)

for..in循环将迭代所有自己的可枚举属性,以及继承的可枚举属性。这就是你在循环中看到getFullName的原因。

但在第二种情况下,它仅列出obj的属性,实际上只有ab属性cd属性对象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