简体   繁体   English

数组属性上Object.create的怪异行为

[英]Weird behaviour with Object.create on array properties

When creating a new object using Object.create() with a prototype object, it seems that the new object keeps a REFERENCE to the prototype for array properties. 使用Object.create()和原型对象创建新对象时,新对象似乎对数组属性保留对原型的引用。

Example Code 范例程式码

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

Result 结果

obj2 color = ["white","blue","red","yellow"], obj2.cat = Fluffy, state = {"complete":false}
obj color = ["white","blue","red","yellow"], obj.cat = Kitty, state = {}

The string property 'cat' in the new obj2 has the expected behaviour and is independent from that property in the prototype object 'obj'. 新obj2中的字符串属性“ cat”具有预期的行为,并且与原型对象“ obj”中的该属性无关。 Same with the object property 'state'. 与对象属性“状态”相同。

However, on the array 'color', when I change the array, it also changes on the prototype object! 但是,在数组“颜色”上,当我更改数组时,它也在原型对象上也发生了变化!

Is that intended in Javascript? 这是用Java编写的吗? For me, coming from an object-oriented background, this is totally unexpected. 对我而言,这是来自面向对象的背景,这完全是意外的。 I see no logic in that. 我认为这没有逻辑。 What is different about an array? 数组有什么不同?

I could even see some logic if value-types like strings would behave different than an object property but they do not (as this example shows) - yet arrays behave differently. 如果像字符串这样的值类型在行为上与对象属性不同,但它们却没有(如本例所示),则我什至可以看到一些逻辑-数组的行为也有所不同。

Assignment to an object property: 分配给对象属性:

obj.xyz = "hello world";

always updates (creating if necessary) the property directly on the target object. 总是直接在目标对象上更新(如果需要,创建)属性。

Pushing values into an array, however, does not constitute "assignment to an object property". 但是,将值推入数组并不构成“分配给对象属性”。 Note that, given your code, 请注意,鉴于您的代码,

obj2.color = ["green"];

will create a new "color" property directly on the target object. 将直接在目标对象上创建一个新的“颜色”属性。

In the statement 在声明中

obj2.color.push('blue');

the "color" property is found in the look-up operation on the prototype object. 在原型对象的查找操作中找到“颜色”属性。 Then, via that object reference (the reference to the "color" property on the prototype), the "push" property is looked up. 然后,通过该对象引用(对原型上“ color”属性的引用),查找“ push”属性。 That's found eventually on the Array.prototype object. 最终可以在Array.prototype对象上找到。 Then that value is called as a function. 然后将该值称为函数。 Nothing in that process involves updating a property value on "obj2". 在此过程中,没有任何事情涉及更新“ obj2”上的属性值。

That the "color" property on the prototype is an array is not particularly special. 原型上的“颜色”属性是数组并不是特别特殊。 You'll see similar effects for any object reference. 对于任何对象引用,您都会看到类似的效果。 Consider: 考虑:

var proto = { obj: { a: 1, b: 2 } };
var obj2 = Object.create(proto);
obj2.obj.a = 3;

That will change the "obj" object in the prototype. 这将更改原型中的“ obj”对象。

It should be noted finally that usually the prototype is the source of function references, not simple values. 最后应该指出的是, 通常原型是函数引用的来源,而不是简单的值。

TLDR: setting a property of an object sets it directly on that object. TLDR:设置对象的属性可直接在该对象上设置它。 Getting a property goes up the prototype chain. 获取属性沿原型链上升。

 obj2.color

That gets the array of the prototype. 那得到原型的阵列。

In addition to Pointy's well explained answer , you can do something like this to create a deep cloned object. 除了Pointy解释清楚的答案外 ,您还可以执行类似的操作来创建深度克隆的对象。

Note though, as commented by Pointy, this might not work on "all" objects. 但是请注意,正如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)); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM