2010-07-07 89 views
11

我遇到道格拉斯康乐福的Object.create方法,我希望有人也许能够解释一个特点:如果我创建一个对象的JavaScript的Object.create - 继承嵌套属性

- 说“人' - 使用对象字面符号,然后使用Object.create创建一个新对象 - 比如'anotherPerson' - 它继承了最初的'person'对象的方法和属性。

如果我然后更改第二个对象的名称值 - 'anotherPerson' - 它也会更改初始'person'对象的名称值。

这只是发生在属性嵌套,这段代码应该给你什么,我的意思是一个想法:

if (typeof Object.create !== 'function') { 
    Object.create = function (o) { 
     function F() {} 
     F.prototype = o; 
     return new F(); 
    }; 
}; 

// initiate new 'person' object 
var person = { 
    name: { 
     first: 'Ricky', 
     last: 'Gervais' 
    }, 
    talk: function() { 
     console.log('my name is ' + this.name.first + ' ' + this.name.last); 
    } 
} 

// create anotherPerson from person.prototype 
var anotherPerson = Object.create(person); 
// change name of anotherPerson 
anotherPerson.name.first = 'Stephen'; 
anotherPerson.name.last = 'Merchant'; 

// call talk method of both 'person' and 'anotherPerson' objects 
person.talk(); // oddly enough, prints 'Stephen Merchant' 
anotherPerson.talk(); // prints 'Stephen Merchant' 

如果我存储的名称值,而不嵌套那么这种奇怪的行为不会发生 - - 例如

// initiate new 'person' object 
var person = { 
    firstName: 'Ricky', 
    lastName: 'Gervais', 
    talk: function() { 
     console.log('my name is ' + this.firstName + ' ' + this.lastName); 
    } 
} 

// create anotherPerson from person.prototype 
var anotherPerson = Object.create(person); 
// change name of anotherPerson 
anotherPerson.firstName = 'Stephen'; 
anotherPerson.lastName = 'Merchant'; 

// call talk method of both 'person' and 'anotherPerson' objects 
person.talk(); // prints 'Ricky Gervais' 
anotherPerson.talk(); // prints 'Stephen Merchant' 

当使用具有构造函数和'new'关键字的古典风格的继承时,似乎不会出现这种嵌套问题。

如果有人能够解释为什么会发生这种情况,我会非常感激!

+2

可能的重复:[克罗克福德的原型继承 - 嵌套对象的问题](http://stackoverflow.com/q/10131052/1048572) – Bergi 2014-06-08 12:59:55

回答

18

这是因为anotherPerson.name是一个对象,它是上存储在原型链,原来person对象:

//... 
var anotherPerson = Object.create(person); 
anotherPerson.hasOwnProperty('name'); // false, the name is inherited 
person.name === anotherPerson.name; // true, the same object reference 

可以通过分配新对象的新的name财产避免这种创建的对象:

// create anotherPerson from person 
var anotherPerson = Object.create(person); 

anotherPerson.name = { 
    first: 'Stephen', 
    last: 'Merchant' 
}; 
+0

哇,堆栈溢出比论坛更像是即时通讯工具!感谢你的回应,这是有道理的 - 所以第二个对象只有引用的名称对象,它并没有被实际复制。然后我假设原来的'person'对象会评估hasOwnProperty('name')=== true,因为它是'anotherPerson'的原型。 – Richard 2010-07-07 00:41:34

+1

我是Javascript新手,但我猜你也可以使用:'anotherPerson.name = Object.create(person.name);'如果需要,可以使新的嵌套对象从旧的嵌套对象继承。 – 2013-09-25 09:51:15

+0

这已经是一个旧的答案,但我仍然有这个问题。我知道B.name不存在,它会查找A.name,从而替代A.name的值。但是,为什么在第二个例子中,“B.firstName/lastName”存在于B对象中,并且没有覆盖A的属性? – user2734550 2016-05-06 23:11:25

2

问题是Object.create只做浅拷贝而不是深拷贝,所以person.name和anotherPerson.name都指向同一个Object实例。

编辑

虽然这是事实,person.name === anotherPerson.name,我为什么这是真实的解释是不正确。请参阅@ CMS的正确解释。

+2

真的,都指向同一个实例,但实际上,'Object.create' doesn根本不会生成对象副本,它只是创建一个新的*空对象*,它从原始对象中继承*。 – CMS 2010-07-07 00:39:02

+0

感谢您的回复。你知道浅拷贝和深拷贝的任何像样的文章吗? – Richard 2010-07-07 00:43:35

+0

@CMS,其实'F.prototype = o;'是一个副本。它将对象及其属性复制到新对象的原型中......并且不复制'name'属性的原因是因为JavaScript中的对象文字始终是引用,因此引用被复制(而不是其内容)。 ..所以这不是因为它在原型链中更深或者因为它正在做一个浅拷贝。 – 2010-07-07 00:43:37

1

name的属性不被复制的原因是因为在JavaScript对象文字是总是引用,所以引用被复制(而不是它内容)......所以这不是因为它在原型链中更深,或者因为它在做一个浅拷贝。

+0

这对我来说非常有意义。它仍然是正确的吗? – ryansstack 2015-04-01 20:53:23