125

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
}
Boann
  • 48,794
  • 16
  • 117
  • 146
ChrisRich
  • 8,300
  • 11
  • 48
  • 67
  • 24
    Why the heck is this marked as duplicate!?! The other question, and answers, don't even mention `Object.create`. This is a mistake, and should be reopened. – Scott Rippey Oct 09 '14 at 22:55
  • 2
    If anything, it's a duplicate of http://stackoverflow.com/questions/4166616/understanding-the-difference-between-object-create-and-new-somefunction-in-j – Scott Rippey Oct 09 '14 at 22:57
  • 2
    13 votes on that comment and still not reopened..?! – T J Nov 18 '15 at 20:07

5 Answers5

115

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.

Sébastien
  • 11,860
  • 11
  • 58
  • 78
The Alpha
  • 143,660
  • 29
  • 287
  • 307
  • 6
    Hi 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: http://jsfiddle.net/NhQGB/ – ChrisRich Oct 28 '12 at 10:08
  • I'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? – ChrisRich Oct 29 '12 at 01:35
  • so 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? – davidjnelson Aug 13 '14 at 03:33
  • Doest this "MyClass.prototype = new SomeBaseClass()" mean that new instance of SomeBaseClass is created when instance of MyClass is not created yet? –  Dec 15 '14 at 15:46
  • No, only when you create the main object the prototype is set to that `SomeBaseClass`. – The Alpha Dec 15 '14 at 17:49
  • 1
    there are a profusion of topics concerning that yet no explanation like yours. +1 – Soner from The Ottoman Empire Sep 01 '20 at 20:07
40

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.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
8

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.

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • 7
    `Object.create` can't really replace the classical approach with `new` when a constructor function is needed – Bergi Oct 23 '12 at 23:25
  • 1
    It most definitely can @Bergi. Look at this blog post: http://davidwalsh.name/javascript-objects-deconstruction. You can also pass an initialization object as a second parameter to Object.create(). – LocalPCGuy Apr 17 '15 at 15:36
  • @LocalPCGuy: No it cannot, because `Object.create` does not call a function that would be necessary to create closures. Of course, with `Object.create` you can put an `init` method on your objects and call that immediately and it maybe even returns `this` so that you get concise syntax - but wait, that *is* a constructor then. – Bergi Apr 18 '15 at 11:13
  • 1
    Calling 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'. – LocalPCGuy Apr 18 '15 at 15:21
  • Well, 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 prefer `new X` over `Object.create(x).init()`. – Bergi Apr 18 '15 at 16:00
0

I am not an expert in java script but here is a simple example to understand difference between "Object.create" and "new" ..

step 1 : create the parent function with some properties and actions..

function Person() {

this.name = 'venkat';

this.address = 'dallas';

this.mobile='xxxxxxxxxx'

}

Person.prototype.func1 = function () {

    return this.name + this.address;
}

step 2 : create a child function (PersonSalary) which extends above Person function using New keyword..

function PersonSalary() {
    Person.call(this);
}
PersonSalary.prototype = new Person();

PersonSalary();

step 3 : create second child function (PersonLeaves) which extends above Person function using Object.create keyword..

function PersonLeaves() {
 Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);


PersonLeaves();

// Now check both child functions prototypes.

PersonSalary.prototype
PersonLeaves.prototype

both of these child functions will link to Person(parent function) prototype and can access it's methods but if you create child function using new it will return a brand new object with all parent properties which we don't need and also when you create any object or function using "New" that parent function is executed which we don't want to be.

Here are the takeaways

if you just want to delegate to some methods in parent function and don't want a new object to be created , using Object.create is best way.

Venkat
  • 551
  • 6
  • 17
0

A couple of additions to this answer set, mindful that JS obviously now has native classes:

  1. In both Example A and Example B the static inheritance chain is not configured.
  2. In Example B the superclass constructor is run at the "wrong time". It is run before the call to instantiate an instance of the subclass, before any arguments are known and perhaps before you have decided to instantiate an instance of the subclass. Note that constructors can contain any logic they like, including side-effectful logic, so this can be impactful.

Post-ES6 the inheritance chain can be configured in a standardised way using the class and extends keywords (which solve both of these issues).

See also.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331