使用带有原型对象的Object.create()创建新对象时,似乎新对象保留了对数组属性原型的参考。
示例代码
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'具有预期的行为,并且独立于原型对象'obj'中的该属性。与对象属性'state'相同。
但是,在数组'color'上,当我更改数组时,它也会在原型对象上发生变化!
这是用于Javascript吗?对我来说,来自面向对象的背景,这是完全出乎意料的。我认为没有逻辑。阵列有什么不同?
我甚至可以看到一些逻辑,如果像字符串这样的值类型与对象属性的行为不同,但它们没有(如本例所示) - 但数组的行为却不同。
答案 0 :(得分:3)
分配给对象属性:
obj.xyz = "hello world";
始终直接在目标对象上更新(必要时创建)属性。
将值推送到数组中不构成"赋值给对象属性"。请注意,根据您的代码,
obj2.color = ["green"];
将创造一种新的颜色"直接在目标对象上的属性。
声明
obj2.color.push('blue');
"颜色"在原型对象的查找操作中找到属性。然后,通过该对象引用(对原型的"颜色"属性的引用)," push"查找财产。最终在Array.prototype对象上找到了。然后将该值称为函数。该过程中的任何内容都不涉及更新" obj2"。上的属性值
" color"原型上的属性是一个数组并不是特别特别。您将看到任何对象引用的类似效果。考虑:
var proto = { obj: { a: 1, b: 2 } };
var obj2 = Object.create(proto);
obj2.obj.a = 3;
这将改变" obj"原型中的对象。
最后应该注意通常原型是函数引用的来源,而不是简单的值。
答案 1 :(得分:2)
TLDR:设置对象的属性会直接在该对象上设置它。获得房产可以上升到原型链。
obj2.color
获得原型的数组。
答案 2 :(得分:1)
除了Pointy's well explained answer之外,您还可以执行以下操作来创建深度克隆的对象。
但请注意,正如Pointy评论的那样,这可能对“所有”对象无效。
var new_obj = JSON.parse(JSON.stringify(old_obj));`
Stack snippet
var obj = { color: ['white'], cat: 'Kitty', state: {}};
var obj2 = JSON.parse(JSON.stringify(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));