I have a question about the following canonical object.create method:
Object.create = function(o, props) {
function F() {}
F.prototype = o;
if (typeof(props) === "object") {
for (prop in props) {
if (props.hasOwnProperty((prop))) {
F[prop] = props[prop];
}
}
}
return new F();
};
On line 3 of the above code we set the prototype property of the F object to the o argument's prototype.
I would have thought this meant that both o and F point to the same prototype and therefore point to the same set of members.
But the code then goes onto copy all the members in the prop in props loop.
What is the point of setting the prototype in line 3 if we then go onto copy all the members manually?
There's a mistake in the version of Object.create
in your question: The loop attaches the properties to the constructor function F
(not to the returned object, or its prototype) which means they're not accessible in the created object.
The properties of the second parameter to Object.create
are supposed to be copied to the newly created object. The Mozilla documentation for Object.create
puts it like this:
If specified and not undefined, an object whose enumerable own properties (that is, those properties defined upon itself and not enumerable properties along its prototype chain) specify property descriptors to be added to the newly-created object, with the corresponding property names.
Try running the following code with the version of Object.create
in the question:
o = Object.create(
{a: "prototype's a", b: "prototype's b"},
{a: "object's a"}
);
You'll find that o.a == "prototype's a"
and o.b == "prototype's b"
, "object's a"
is lost.
The following version of the function would probably be more useful:
Object.create = function(o, props) {
var newObj;
// Create a constructor function, using o as the prototype
function F() {}
F.prototype = o;
// Create a new object using F as the constructor function
newObj = new F();
// Attach the properties of props to the new object
if (typeof(props) === "object") {
for (prop in props) {
if (props.hasOwnProperty((prop))) {
newObj[prop] = props[prop];
}
}
}
return newObj;
};
Let's try it out with the same example:
o = Object.create(
{a: "prototype's a", b: "prototype's b"},
{a: "object's a"}
);
The new object o
is created with a prototype that has properties a
and b
and it's own property a
.
Let's look at o.b
first: o.hasOwnProperty("b")
will return false
, because o
does not have a property called b
. That's where the prototype comes in; because there is no property b
it is looked up on the prototype, and therefore o.b === "prototype's b"
.
On the other hand, o.hasOwnProperty("a")
will return true
, because o
does have an a
property. o.a == "object's a"
and nothing is looked up from the prototype.
As pointed out in @chuckj's answer, the correct implementation of Object.create
is more complicated than this. For more details, see John Resig's post on ECMAScript 5 Objects and Properties.