Reputation: 123178
I've been reading Is JavaScript's "new" keyword considered harmful? and this Adobe Article on using prototypal inheritance rather than 'new'. The Adobe article has a 'new' example:
function Foo() {
this.name = "foo";
}
Foo.prototype.sayHello = function() {
alert("hello from " + this.name);
};
...that it replaces with:
var foo = {
name: "foo",
sayHello: function() {
alert("hello from " + this.name);
}
};
Here the 'sayHello' method isn't attached to the object's prototype
. Doesn't this mean 'sayHello' gets unnecessarily duplicated in memory (I know V8 avoids this, but in older JS engines, for example) as it is copied to all objects that inherit from foo
?
Shouldn't it be:
var foo = {
name: "foo",
prototype: {
sayHello: function() {
alert("hello from " + this.name);
}
}
};
Or similar?
Upvotes: 1
Views: 72
Reputation: 123178
Going to answer my own question here, for my own notes and also to help explain to others:
Q. Using Object.create(), should exemplars have methods attached to their
prototype
property?
A. No, because Object.create(parentObject) itself sets up the parentObject as the prototype
of a dynamically-created constructor.
Also: prototype
is always a property on constructor Functions - not on regular Objects. Eg:
var someArray = [];
someArray.__proto__ === Array.prototype
Object.create() dynamically creates constructors, setting the prototype on them to the object in its first argument.
Upvotes: 0
Reputation: 92274
No, it won't get duplicated if you create another object using that as a protoype. The almost equivalent code using Object.create
is actually slightly different, you are not using the prototype, you are just creating an object. To use prototypal inheritance, do the following. Note that using new
still sets up the prototype chain so the title of the article you linked to is not very accurate and you are still sharing the properties on a single object.
var foo = {
name: "foo",
sayHello: function() {
alert("hello from " + this.name);
}
};
var extended = Object.create(foo);
var extended2 = Object.create(foo);
extended.name = "first";
extended2.name = "second";
extended.sayHello(); // hello from first
extended2.sayHello(); // hello from second
// Methods are shared, outputs true
console.log(extended.sayHello === extended2.sayHello)
// Now if you delete the property again, it will go up the chain
delete extended.name;
extended.sayHello(); // hello from foo
You could also just do
var extended = Object.create(Foo.prototype);
It would get duplicated if you create a constructor to get new instances instead of Object.create
or new Foo
function createFoo() {
return {
name: "foo",
sayHello: function() {
alert("hello from " + this.name);
}
}
}
var a = createFoo();
var b = createFoo();
// The function objects are not shared
alert('Are functions the same? ' + a.sayHello === b.createFoo);
They would also not be shared if you use the closure approach to creating objects. Crockford suggests that to create truly private members. I don't use it because it doesn't use the prototype chain and inheritance is tricky to implement without just copying properties.
Function Foo() {
var name = 'foo';
this.sayHello = function () {
alert(name);
};
this.setName = function (newName) {
name = newName;
};
}
var a = new Foo();
var b = new Foo();
console.log(a.sayHello === b.sayHello); // outputs false
Upvotes: 2
Reputation: 48230
The method is not attached to the prototype because this very object becomes the prototype that is attached to newly created objects with Object.create
. And you don't need a prototype of the prototype.
Remember that Object.create
doesn't deep clone objects. Rather, it is equivalent to something like
Object.create = function(proto) {
function F() {}
F.prototype = proto;
return new F();
}
(actual implementation is more complicated but this short version illustrates the idea)
All newly created objects "inherit" the method from the foo
which acts as the prototype and there is no duplication here.
Upvotes: 2