JavaScript inheritance: Object.create vs new
Solution 1
In your question you have mentioned that Both examples seem to do the same thing
, It's not true at all, because
Your first example
function SomeBaseClass(){...}
SomeBaseClass.prototype = {
doThis : function(){...},
doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
In this example, you are just inheriting SomeBaseClass' prototype
but what if you have a property in your SomeBaseClass
like
function SomeBaseClass(){
this.publicProperty='SomeValue';
}
and if you use it like
var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);
The obj
object won't have publicProperty
property like in this example.
Your second example
MyClass.prototype = new SomeBaseClass();
It's executing the constructor
function, making an instance of SomeBaseClass
and inheriting the whole SomeBaseClass
object. So, if you use
var obj=new MyClass();
console.log(obj.publicProperty); // SomeValue
console.log(obj);
In this case its publicProperty
property is also available to the obj
object like in this example.
Since the Object.create
is not available in some old browsers, in that case you can use
if(!Object.create)
{
Object.create=function(o){
function F(){}
F.prototype=o;
return new F();
}
}
Above code just adds Object.create
function if it's not available so you can use Object.create
function and I think the code above describes what Object.create
actually does. Hope it'll help in some way.
Solution 2
Both examples seem to do the same thing.
That's true in your case.
When would you chose one over the other?
When SomeBaseClass
has a function body, this would get executed with the new
keyword. This usually is not intended - you only want to set up the prototype chain. In some cases it even could cause serious issues because you actually instantiate an object, whose private-scoped variables are shared by all MyClass
instances as they inherit the same privileged methods. Other side effects are imaginable.
So, you should generally prefer Object.create
. Yet, it is not supported in some legacy browsers; which is the reason you see the new
-approach much too frequent as it often does no (obvious) harm. Also have a look at this answer.
Solution 3
The difference becomes obvious if you use Object.create()
as it is intended. Actually, it does entirely hideout the prototype
word from your code, it'll do the job under the hood. Using Object.create()
, we can go like
var base = {
doThis : function(){
},
doThat : function(){
}
};
And then we can extend/inherit other objects from this
var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally
So this is another concept, a more "object oriented" way of inherting. There is no "constructor function" out of the box using Object.create()
for instance. But of course you could just create and call a self defined constructor function within those objects.
One argument for using Object.create()
is that it might look more natural to mix/*inherit* from other objects, than using Javascripts default way.
Comments
-
ChrisRich about 4 years
In JavaScript what is the difference between these two examples:
Prerequisite:
function SomeBaseClass(){ } SomeBaseClass.prototype = { doThis : function(){ }, doThat : function(){ } }
Inheritance example A using Object.create:
function MyClass(){ } MyClass.prototype = Object.create(SomeBaseClass.prototype);
Inheritance example B using the new keyword
function MyClass(){ } MyClass.prototype = new SomeBaseClass();
Both examples seem to do the same thing. When would you chose one over the other?
An additional question: Consider code in below link (line 15), where a reference to the the function's own constructor is stored in the prototype. Why is this useful?
https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js
Excerpt (if you don't want to open the link):
THREE.ImageLoader.prototype = { constructor: THREE.ImageLoader }
-
Bergi over 11 years
Object.create
can't really replace the classical approach withnew
when a constructor function is needed -
ChrisRich over 11 yearsHi Sheikh. Thanks for your efforts on this. Yes, the differences is that the constructor is ran in the second example but not in the first. (which is desirable in my case). Regarding the undefined public property that is not inherited from the super implementation, you just need to call super in the child's constructor: SomeBaseClass.call(this). Check this fiddle: jsfiddle.net/NhQGB
-
ChrisRich over 11 yearsI've been looking for a super simple way of proper inheritance in JS without using any libraries / frameworks. I think this example (in my fiddle above) is the best approach for modern browsers. Perhaps the Object.Create polyfill could add support for legacy browsers?
-
spex over 10 yearsThis is the best answer, well explained
-
davidjnelson almost 10 yearsso basically to summarize, if you do .prototype = new then you are inheriting any values you assigned to this in the base class, and when you do object.create you are ONLY inheriting what is on the prototype in the base class, right?
-
Admin over 9 yearsDoest this "MyClass.prototype = new SomeBaseClass()" mean that new instance of SomeBaseClass is created when instance of MyClass is not created yet?
-
The Alpha over 9 yearsNo, only when you create the main object the prototype is set to that
SomeBaseClass
. -
LocalPCGuy about 9 yearsIt most definitely can @Bergi. Look at this blog post: davidwalsh.name/javascript-objects-deconstruction. You can also pass an initialization object as a second parameter to Object.create().
-
Bergi about 9 years@LocalPCGuy: No it cannot, because
Object.create
does not call a function that would be necessary to create closures. Of course, withObject.create
you can put aninit
method on your objects and call that immediately and it maybe even returnsthis
so that you get concise syntax - but wait, that is a constructor then. -
LocalPCGuy about 9 yearsCalling an init function works similarly to a constructor, but it is not a constructor. And that method does allow you exactly replace the classical approach with Object.create. And the mental model of the object linkage is much simpler than the one created via 'new'.
-
Bergi about 9 yearsWell, my mental model of
new
uses "object linkage", so there's not much difference. In fact, there are only two things:.constructor
is called.init
, and that function doesn't have a.prototype
property pointing back to your prototype object. The rest is just syntax - and I prefernew X
overObject.create(x).init()
. -
Soner from The Ottoman Empire almost 4 yearsthere are a profusion of topics concerning that yet no explanation like yours. +1