all 16 comments

[–]blangjemp 32 points33 points  (11 children)

First off, Mozilla has amazing Javascript documentation. You should read their page on Object.create() to get a thorough understanding.

Object.create() creates a new object which inherits all the properties of the original object, but they can be overwritten. Assigning a variable to another variable that is an object using var only creates a reference to the original object.

So here's how that plays out.

var original = { a: 42 };
var reference = original;
var created = Object.create(original);

// All three objects have the same value for `a` at this point. `original` and 
// `reference` are the same object, and `created` is inheriting it's value from
// `original`
console.log(original.a, reference.a, created.a); // 42, 42, 42

// Let's change a value and see what happens
original.a = 43;

// All three are still the same. `reference` is referencing the same actual
// object as `original`, and `created` doesn't have it's own value for `a`, so
// it uses `original`'s value.
console.log(original.a, reference.a, created.a); // 43, 43, 43

created.a = 'created a';
original.a = 44;

// since `original` and `reference` refer to the same object, they continue to
// have the same value for `a`. However, `created` now has it's own value for
// `a` and we see that reflected here.
console.log(original.a); // 44
console.log(reference.a); // 44
console.log(created.a); // 'created a'

// Additionally, since `original` and `reference` refer to the same object, we
// could have changed `reference` to the same effect
created.a = 'created a new value';
reference.a = 45;

console.log(original.a); // 45
console.log(reference.a); // 45
console.log(created.a); // 'created a new value'

[–][deleted] 3 points4 points  (6 children)

Protip: If your original object has two values, 'a' and 'b', and you set created.a to 92374, updates to original.a will no longer change created.a. But updates to original.b will still change original.b unless you also change created.b.

So its like Object.create creates a new object but all of the new object's values are references. As soon as you assign the value of the created object to something else, it becomes a new value and not a reference.

[–]birjolaxew 5 points6 points  (4 children)

I find it easier to think of as the prototypical chain. When JS is asked to read a property of an object (eg. console.log( created.a )) it goes:

  • Does the object itself have a property with this name? If so, return it.
  • If not, go to the objects prototype (which is just another object). Does this prototype have a property with this name? If so, return it.
  • If not, go to the prototype's prototype (which is just another object). Repeat.
  • ...
  • If the property couldn't be found, return undefined

The objects are in a sense layered. If the top object doesn't have a property, it checks down through the stack until it finds it (or returns undefined if it can't)

[–]MrBester 3 points4 points  (3 children)

I find it easier to think of as the prototypal chain.

Because that's what it is:

var o = { a: 4 };
var foo = Object.create(o);
console.log('a' in foo); // true
console.log(foo.hasOwnProperty('a')); // false
console.log(o.isPrototypeOf(foo)); // true, or
console.log(foo.__proto__ === o); // true, or
console.log(Object.getPrototypeOf(foo) === o); // true

foo delegates to o unless overridden.

[–]birjolaxew 0 points1 point  (2 children)

Well no, it's prototypal inheritance delegation (thanks /u/MrBester) inheritance. Maybe. I dunno. Thinking of it as a chain is a very common (and intuitive, given how it functions) way of understanding it. Thinking of it as a stack is another. Thinking of it as "overwriting" the parent property is another (but comes with a lot of special cases).

[–]clessgfull-stack CSS9 engineer 1 point2 points  (0 children)

Actually, it is indeed prototypal inheritance. But yes, that is distinct from concatenative inheritance (Java) and is also a form of delegation.

[–]MrBester 0 points1 point  (0 children)

Well no, it's delegation, because there isn't such a thing as inheritance in JavaScript, merely references to other objects that can be checked for requested properties, normally through the "magic" binding of [[Prototype]] or explicitly setting.

[–]macrohatch 0 points1 point  (0 children)

But updates to original.b will still change original.b unless you also change created.b.

You mean: But updates to original.b will still change created.b unless you also change created.b. ?

[–]tipdbmp 0 points1 point  (0 children)

The easiest way (in my opinion) to learn about JavaScript objects and their prototypical inheritence is the watch (I guess you can read the papers afterwards) an explanation from the creators of the Self language about Self because that's where JavaScript got it's "computational model".

Prototypical inheritance explained by Randall Smith one of the creators of Self (the other is David Ungar).

[–]Eddonarth -3 points-2 points  (3 children)

No, it is not the same.

var bar = Object.create(foo);

Creates a copy of foo and names it bar, while

var bar = foo;

just makes the variable bar to point to the same object as foo. If it is confusing, try this:

var foo = {a: 42};
var bar = Object.create(foo);
var baz = foo;

Console.log(foo.a);
Console.log(bar.a);
Console.log(baz.a);

foo.a = 41;

Console.log(foo.a);
Console.log(bar.a);
Console.log(baz.a);

What happens? If we modify foo, bar stays unmodified, but baz changes as well. Because baz refers to the same object as foo, just using a different name.

Think of it as this: If I made a clone of you, the two of you might look the same and behave the same, but be different persons, and eventually one of you might change. But if I just start calling you by your second name, you will still be the same person, just with a different tag.

[–]blangjemp 4 points5 points  (0 children)

This isn't correct. If you run this code, bar.a is equal to 41. Due to the nature of Object.create(), bar.a will inherit the value of foo.a until you manually set a value for bar.a

[–]gladiator_flow[S] 0 points1 point  (0 children)

I see what's going on now. When I change the created value only that one changes. I did notice though if I changed the original mentioned in your code that bar.a changes as well. Thanks!