1

I am learning the js prototype, and I am wondering if there are any differences between the following two segment?

Segment1:

function SuperType(){
    this.color=["blue","yellow"];
}


function SubType(){

}      
Subtype.prototype = new SuperType();

Segment2:

function SuperType(){
    this.color=["blue","yellow"];
}

function SubType(){
    SuperType.call(this);
}   

and if the above two does the same thing, then why some codes bother to do this:

function SubType(){

        SuperType.call(this); 
        }

SubType.prototype=new SuperType(); 
Blake
  • 7,367
  • 19
  • 54
  • 80
  • Prototype is shared, this.something is instance specific. Its explained in detail here.http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Apr 21 '14 at 01:15

4 Answers4

2

Yes, there are differences.

In Segment 1, the subclass SubType does not call the constructor of SuperType so it never gets executed. Segment 1 is not a correct general purpose way to inherit from another object.

In Segment 2, the subclass SubType does call the constructor of SuperType so the statement this.color=["blue","yellow"]; gets executed, but the prototype is not set appropriately so any prototype items that SuperType might have had are not inherited. Segment 2 is not a correct general purpose way to inherit from another object.

Segment 1 would work properly if there was no code in the SuperType constructor (not the case in your example). As you show it, because the SuperType() constructor is not called, this.color would only be in the prototype and thus the same array would be shared by all instances which is generally NOT what you want. Calling the constructor properly would give every instance it's own copy of this.color, not a shared copy.

Segment 2 would work properly if nothing was added to the SuperType prototype and there are no constructor arguments for SuperType (happens to be the case in your example, but not a good general practice).

Neither is a good general purpose way of doing things.


Your last option is the proper general purpose way to do things because it both inherits from the prototype AND it executes the constructor of the inherited object.


The most general purpose way also passes any constructor arguments to the inherited object using .apply(this, arguments) like this and initializes its own prototype and sets it's constructor property.

// define base object constructor
function SuperType(){
    this.color=["blue","yellow"];
}

// define base object methods on the prototype
SuperType.prototype.foo = function() {};

// ---------------------------------------------------------------------------

// define object that wants to inherit from the SuperType object
function SubType() {
    // call base object constructor with all arguments that might have been passed
    SuperType.apply(this, arguments); 
}

// set prototype for this object to point to base object
// so we inherit any items set on the base object's prototype
SubType.prototype = new SuperType();
// reset constructor to point to this object not to SuperType
SubType.prototype.constructor = SubType;

// define any methods of this object by adding them to the prototype
SubType.prototype.myMethod = function() {};

If you are willing to only support IE9 and above, then you should change this line:

SubType.prototype = new SuperType();

to this:

SubType.prototype = Object.create(SuperType.prototype);

This avoids calling the SuperType() constructor in order to just get an object to use for the prototype. In most cases this really doesn't matter, but in cases where the constructor has side effects outside of just initializing it's own properties, it can matter.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • @ThorstenArtner'Austria' - `Object.create()` is a better to go if you are willing to only support IE9 and above. But, in this case (and in most cases), there is no downside to doing it this way. The object will end up with the exact same properties either way. Please explain any practical difference in the OP's case or in any common case. – jfriend00 Apr 20 '14 at 19:52
  • @ThorstenArtner'Austria' - I've already read your answer. You haven't explained any practical consequences to doing it the way I proposed (so what if there's an extra copy of something in the prototype - it doesn't have any practical consequences in this example). In any case, I've also added a note to my answer about using `Object.create()` instead if you are willing to only support IE9 and above. – jfriend00 Apr 20 '14 at 19:56
  • the problems happen when people forget to call the super constructor than the variables are still defined in the instances but not as own properties of the instances. and the second thing is. if you have more complexer programming and inheritance you have defined variables in the prototypes where you dont need it and also you are executing constructors where is no need of -> takes time –  Apr 20 '14 at 20:22
  • thanks for your detailed answer! but what does it mean by "the statement this.color=["blue","yellow"] is not executed?"if I do var `instance1= new SubType()`; and do `console.log(instance1.color)`, I can still see the color is not null – Blake Apr 20 '14 at 20:25
  • and what is the difference if `constructor ` is called or not? – Blake Apr 20 '14 at 20:27
  • If the parent class constructor is NOT called, then the parent object may not be initialized properly. It all depends upon what the constructor does. In your example, it did not do harm. But imagine if the constructor created other objects, bound things to the DOM, did an Ajax call, etc... If you don't call the base object constructor, none of that base object initialization is done. Your example is so trivial that the color initialization is coming from the prototype that is being inherited so it still works. But, that isn't the general solution that always works. – jfriend00 Apr 20 '14 at 20:56
  • if the constructor makes an ajax call and bind things to the dom then you cant inherit with prototype=new constructor than a ajax call is made or things are bounded only by prototype inheritation where you dont want it or what do you mean=? –  Apr 20 '14 at 21:04
  • 1
    @ThorstenArtner'Austria' - yep, that would be true - you would want to use `Object.create()` or a polyfill for it when setting up the prototype or make the object require an `.init()` call for that kind of stuff which is another common work-around. The point is that the base object constructor should be called in construction of the derived object. Let's try to stay on point here. – jfriend00 Apr 20 '14 at 21:08
  • the Point is that you can do this also like I wrote below, without polyfil and without Object.create ;) .. i have edited a second Workaround where you even dont Need to put an if condition in the constructor –  Apr 20 '14 at 21:37
  • @Blake - see the comments in my answer I added to my fourth paragraph about segment 1. If you don't call the constructor, then `this.color` is only in the prototype and all instances of the SubType or SuperType objects all share the same color array. If you call the constructor properly, then each instance gets it's own color array (which is usually what you want). Also, if you ever have a constructor argument that the base object needs, you HAVE to call the base object's constructor in order to pass that argument to it. – jfriend00 Apr 20 '14 at 23:37
1

In segment 1 the prototype gets set correctly but the constructor function of SuperType never gets called.

At the start of segment 2 the constructor function of the SuperType gets called but the prototype is not set.

The last example is correct because it sets up the prototype correctly as well as calls the SuperType's constructor function.

function SuperType() {
  // Do some stuff.
}

function SubType() {
  SuperType.apply(this, arguments);
}

SubType.prototype = new SuperType();
Mingle
  • 846
  • 6
  • 13
1

you should not set prototype inheritance with

 SubType.prototype=new SuperType (); 

because there can be problems.

if you do that like this, the prototype of SubType would also inherit the property color as own property of the SubType prototype, because the constructor is worked through. Every new instance of subType has then a reference to the color property in the prototype and is not an own property of the instance itself, this is finally not what you want because you only want to inherit the prototype. the luck is that after calling the super constructer every instance gets an own color property , but the color property is still also defined in the prototype. there is no need

so to really inherit only the prototype you should use Object.create or do a workaround like this.

function SuperType()
  {
  if (SuperType.doNotConstruct) return;
  this.color=["blue","yellow"];
  }


function SubType()
  {
  SuperType.call (this);
  }      

SuperType.doNotConstruct=true;

SubType.prototype = new SuperType();

SuperType.doNotConstruct=false;

SubType.prototype.constructor=SubType;

second way - better way - because no if Statement in the constructor is needed

function SuperType()
  {
  this.color=["blue","yellow"];
  }


function SubType()
  {
  SuperType.call (this);
  }      

var CLASS=function () {}
CLASS.prototype=SuperType.prototype;
SubType.prototype=new CLASS ();
SubType.prototype.constructor=SubType;
0

@blake try the following - this will show a problem when people forget to call the super constructor and do inheritation with ...prototype=new constructor

function SuperType()
  {
  this.color=["blue","yellow"];
  }

SuperType.prototype.addColor=function (name)
  {
  this.color.push ("red");
  }


function SubType () {}

SubType.prototype=new SuperType ();

var a=new SubType ();
var b=new SubType ();

a.addColor ("red");

console.log (a.color);
console.log (b.color);
  • So you're trying to train the OP NOT to call the base class constructor. Sure, it doesn't make a difference in this case, but I know of no site that teaches this as a good design pattern or the preferred practice. – jfriend00 Apr 20 '14 at 22:46
  • thats for Blake (its about how problems can build up) because he wrote thanks for your detailed answer! but what does it mean by "the statement this.color=["blue","yellow"] is not executed?"if I do var instance1= new SubType(); and do console.log(instance1.color), I can still see the color is not null – Blake 2 hours ago and what is the difference if constructor is called or not? – Blake 2 hours ago this is not a way to do it, it shows how it should not be done... the second way i edited in my first post –  Apr 20 '14 at 23:20
  • OK, imagine the `SuperType` constructor requires an argument. How does this design pattern work then? – jfriend00 Apr 20 '14 at 23:22
  • i dont know where this discussion goes to now, because we wrote comments above and now here. do you want to talk about the problems which can happen here, or do you want to talk about the second way i edited in my first answer see please write comments above –  Apr 20 '14 at 23:26
  • I think the OP's question has been answered. I just don't think we should be "teaching" methods that don't call the base constructor because those are not general purpose solutions that will always work. – jfriend00 Apr 20 '14 at 23:27
  • again this was an example what can happen if you do not call the superconstructor , this was not an example for how it should be done. a change of the a.color will also effect b.color –  Apr 20 '14 at 23:30
  • Geez, then you SHOULD explain that in your answer. Your answer is pretty meaningless to most without an explanation. – jfriend00 Apr 20 '14 at 23:31