Why is that this code:
var foo = {one: 1, two: 2};
var bar = new Object( foo );
bar.three = 3;
bar.one = 100;
document.write(bar.one); //100
document.write(foo.one); //100
results in bar.one & foo.one being both 100, while
var foo = {one: 1, two: 2};
var bar = Object.create( foo );
bar.three = 3;
bar.one = 100;
document.write(bar.one); //100
document.write(foo.one); //1
only affects bar.one..
My first intuition is that since in the first piece of code we are assigning a foo reference to bar, then it means the change will also apply to foo, while on the second code, it probably 'inherits' from foo, and therefore the change on bar's 'subclass' attribute won;t apply to its 'superclass' (prototype)..
Can somebody please confirm that my assumption is at least on the right track? Would absolutely appreciate any answers. Thanks in advance.
The line:
var bar = new Object( foo );
In your first snippet, it doesn't do anything -you are right with your assumption-, it will simply return a reference to the same object passed to the Object
constructor.
That's the behavior when you pass a native object to the Object
constructor in a new
expression (new Object(value)
), if you pass a host object, the results are implementation dependent.
If you don't pass a value (or you explicitly pass the primitives undefined
or null
) a new object that inherits from Object.prototype
will be created.
Otherwise, if you pass any of the remaining primitives (as a Number, String or a Boolean value), a primitive wrapper object will be created (basically "primitive-to-object" type conversion), for example.
var s = new String("foo"); // a string object wrapper
typeof s; // "object"
s.valueOf(); // "foo"
See this question about primitives and objects: How is a Javascript string not an object?
In your second snippet, the line:
var bar = Object.create( foo );
Creates a new object, that inherits from foo
, and since it's a different object, when you assign the properties:
bar.three = 3;
bar.one = 100;
Those will be created physically on that separated instance, as you can see, the bar.one
property shadows the value contained in foo
.
The object referenced by bar
, in fact will contain two own properties (one
and three
, but since it inherits from foo
, the property named two
is resolvable through the prototype chain, for example:
bar.hasOwnProperty('one'); // true, the property is "own"
bar.hasOwnProperty('two'); // false, the property is "inherited" from foo
bar.two; // 2, is accessible
Basically, the prototype chain of bar
looks like this:
----------------- ========> | Object.prototype| ==> null | ----------------- |-------------| [[Prototype]] |---------| | one: 100 | ====================> | one: 1 | (shadowed) | three: 3 | | two: 2 | |-------------| |---------| (== line denotes the prototype chain)
new Object
and Object.create
do completely different things, despite their similar sounding names.
new Object()
, with no argument, is equivalent to an empty object literal {}
, which you should always use instead. With an argument, new Object(obj)
simply returns the argument.
Object.create(obj)
helps untangle JavaScript's messed up prototypal inheritance. Reading this article by Douglas Crockford will help with that. Basically, it creates a new object that inherits from obj
. So if you have
var obj1 = {x: 1}, obj2 = Object.create(obj1);
obj1.x; // 1
obj2.x; // 1
obj2.x = 42;
obj1.x; // 1
obj1.x = 10;
obj2.x; // 10, since obj2 inherits from obj1, changing obj1's properties
// changes obj2, but not the other way around.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With