当使用带有原型(prototype)对象的 Object.create() 创建新对象时,新对象似乎为数组属性保留了对原型(prototype)的引用。
示例代码
var obj = { color: ['white'], cat: 'Kitty', state: {}};
obj2 = Object.create(obj);
obj2.color.push('blue');
obj2.color.push('red');
obj2.color.push('yellow');
obj2.cat = 'Fluffy';
obj2.state = {complete: false};
console.log('obj2 color = ' + JSON.stringify(obj2.color) + ', obj2.cat = ' + obj2.cat + ', state = ' + JSON.stringify(obj2.state));
console.log('obj color = ' + JSON.stringify(obj.color) + ', obj.cat = ' + obj.cat + ', state = ' + JSON.stringify(obj.state));
结果
obj2 color = ["white","blue","red","yellow"], obj2.cat = Fluffy, state = {"complete":false}
obj color = ["white","blue","red","yellow"], obj.cat = Kitty, state = {}
新 obj2 中的字符串属性“cat”具有预期的行为,并且独立于原型(prototype)对象“obj”中的该属性。与对象属性“state”相同。
但是,在数组 'color' 上,当我更改数组时,它也会在原型(prototype)对象上发生更改!
这是用 Javascript 编写的吗?对于来自面向对象背景的我来说,这是完全出乎意料的。我认为这没有逻辑。数组有什么不同?
如果值类型(如字符串)的行为与对象属性不同,我什至可以看到一些逻辑,但它们不会(如本例所示)——但数组的行为不同。
最佳答案
对象属性的赋值:
obj.xyz = "hello world";
总是直接在目标对象上更新(必要时创建)属性。
但是,将值压入数组不构成“对对象属性的赋值”。请注意,根据您的代码,
obj2.color = ["green"];
将直接在目标对象上创建一个新的“颜色”属性。
在声明中
obj2.color.push('blue');
“颜色”属性是在原型(prototype)对象的查找操作中找到的。然后,通过该对象引用(对原型(prototype)上“color”属性的引用),查找“push”属性。最终在 Array.prototype 对象上找到了它。然后将该值作为函数调用。该过程中没有任何内容涉及更新“obj2”的属性值。
原型(prototype)上的“color”属性是一个数组并不是特别特别。对于任何对象引用,您都会看到类似的效果。考虑:
var proto = { obj: { a: 1, b: 2 } };
var obj2 = Object.create(proto);
obj2.obj.a = 3;
这将改变原型(prototype)中的“obj”对象。
最后应该注意的是,通常原型(prototype)是函数引用的来源,而不是简单的值。
关于javascript - Object.create 在数组属性上的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49557678/