1

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.

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'. 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? 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.

0

3 Answers 3

3

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. That's found eventually on the Array.prototype object. Then that value is called as a function. Nothing in that process involves updating a property value on "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.

It should be noted finally that usually the prototype is the source of function references, not simple values.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks - but this means Object.create does NOT create an entirely new object because it keeps a reference to the prototype. Unthinkable for me with a C# background ... what are my alternatives then if I want a REAL NEW object?
@nepdev yes, that's why it's called the "prototype chain". Every object has a link to the prototype used to construct it, and that prototype object in turn can have a link to the prototype used for its construction, and so on. If you want to make sure that properties are directly on the constructed object, you have to do that explicitly in the constructor or with the new-ish class syntax.
Do I need to use an object constructor with NEW OBJ if I want a REAL NEW object, or is that again the same?
If you perform property value assignments in the constructor (this.foo = "bar";) then you will be creating properties directly on the constructed object. And Object.create() does create an "entirely new object", but properties on the prototype are shared because that's the whole point of prototypal inheritance. It's really quite a bit different than how Java, C#, C++ etc work.
2

TLDR: setting a property of an object sets it directly on that object. Getting a property goes up the prototype chain.

 obj2.color

That gets the array of the prototype.

Comments

1

In addition to Pointy's well explained answer, you can do something like this to create a deep cloned object.

Note though, as commented by Pointy, this might not work on "all" objects.

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

2 Comments

Why use Object.create at all then?!
This is true, but it should be noted that not all objects (or object property values) can be "stringified" as JSON. In particular, function-valued properties will be ignored.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.