Object.create对数组属性的奇怪行为

时间:2018-03-29 13:42:52

标签: javascript

使用带有原型对象的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吗?对我来说,来自面向对象的背景,这是完全出乎意料的。我认为没有逻辑。阵列有什么不同?

我甚至可以看到一些逻辑,如果像字符串这样的值类型与对象属性的行为不同,但它们没有(如本例所示) - 但数组的行为却不同。

3 个答案:

答案 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));