It returns Person
. Why doesn't it return 'John'
?
Because that Object.create
line creates an object with the Person
function as its prototype, and the Person
function object has a surprising definition of the name
property that prevents your writing to it. (The definition makes sense once you know about it, but it's surprising at first.)
What you're creating when you do
john = Object.create(Person);
...is an object that uses the Person
function as its underlying prototype. This doesn't create a Person
instance (which would use Person.prototype
as its prototype), it creates an object that actually uses the function object Person
itself as the prototype.
The Person
function has a non-writable property called name
which is the name of the function (this is not yet in the standard, but it will be in ES6 [currently it's defined in §9.2.11 of the draft spec] and V8 does it already). Because that property is not writable, john.name = 'John'
doesn't do anything. (More on non-writable properties below.)
If your goal was to create a new object with Person.prototype
as the object's underlying prototype, you'd do:
john = new Person();
or
john = Object.create(Person.prototype);
And since Person
accepts an argument, you'd probably do
john = new Person('John');
...rather than assigning to name
afterward.
More on non-writable properties: If you haven't run into them yet, they were defined as part of the 5th edition spec a while back. Here's an example:
var parent = {};
Object.defineProperty(parent, "foo", {
writable: false,
value: "original"
});
The parent
object has an non-writable property, foo
:
console.log(parent.foo); // "original"
parent.foo = "bar";
console.log(parent.foo); // "original"
If we use parent
as a prototype, we still can't write to foo
even on the child object:
var child = Object.create(parent);
console.log(child.foo); // "original"
child.foo = "bar";
console.log(child.foo); // "original"
That's what's happening in your code. parent
is Person
, and child
is john
.
And just to round this out: If we wanted to create a writable property on the child at this point, we could, but just not via assignment we'd have to use defineProperty
:
Object.defineProperty(child, "foo", {
writable: true,
value: child.foo // (just sets the initial value)
});
console.log(child.foo); // "original"
child.foo = "bar";
console.log(child.foo); // "bar"
Now child
has its own property called foo
, which shadows (hides) its prototype's foo
, and is writable.