3

This is the extend function from the book "Pro JavaScript Design Patterns"

function extend(subClass, superClass) {
    var F = function() {};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
    subClass.superclass = superClass.prototype;
    if(superClass.prototype.constructor == Object.prototype.constructor) {
       superClass.prototype.constructor = superClass;
    }
}

I have problems with the first 3 lines... It creates an empty function and then it sets the F.prototype to superClass.prototype which means (for 2 new constructor functions e.g. foo, bar and foo extends bar) that F.prototype will have a constructor property: bar and proto :Object, or not? And on line 3: subClass.prototype = new F(); happens something that I cannot understand.. Why the inheritance happens here when F's [[Prototype]] is Object?


What are the differences between the first 3 lines and

subClass.prototype = new superClass();

when the code executes? I mean how The first does the same as the second one.


Just to add there is a call to the superClass constructor in the subClass. The call is "className".superclass.constructor.call(this);

bliof
  • 2,957
  • 2
  • 23
  • 39

3 Answers3

1
function extend(subClass, superClass) {

    // create a new empty function
    var F = function() {}; 

    // set the prototype of that function to prototype object of the superclass
    F.prototype = superClass.prototype;

    // now set the prototype of the subClass to a new instance of F
    // this is done so that subClass.prototype.foo = does not affect
    // superClass.prototype.foo
    // if you don't do this, changes to one subClass will affect superClass and all
    // other subClasses of superClass
    subClass.prototype = new F();

Note: subClass.prototype = new superClass() would call the constructor and use the returned new object as the prototype. Which would result in properties on superClass itself would turn up on the prototype chain (since that instance is the prototype object).

    // set the constructor, this indicates that 'subClass' is a function
    subClass.prototype.constructor = subClass;

    // add a property to indicate what the superClass is
    // this way one can call super methods via this.superclass.something
    subClass.superclass = superClass.prototype;

    // in case the superClass was an object...
    if(superClass.prototype.constructor == Object.prototype.constructor) {

       // change the constructor?
       // no idea why they do this here
       // this introduces a side effect to the function
       superClass.prototype.constructor = superClass;
    }
}
Ivo Wetzel
  • 46,459
  • 16
  • 98
  • 112
  • You could find an explanation about the last one [here](http://stackoverflow.com/questions/2686258/javascript-inheritance-extend-function). 10x for the comment. – bliof Feb 02 '11 at 20:08
  • @bilof Ah, OK. Still makes little to no sense in an "extend" function, I would not expect that to modify the superClass. – Ivo Wetzel Feb 02 '11 at 20:21
  • Well, it is done to insure that the constructor call in the subClass will work. – bliof Feb 02 '11 at 21:36
  • Hey Ivo -- I saw this thread and I am curious (after a few years), if that last bit makes more sense. I personally am not understanding it fully and wondering if there is a bit more understanding with this: if(superClass.prototype.constructor == Object.prototype.constructor), and why the resetting to superClass. When would the SuperClass constructor be overwritten? – james emanon Feb 17 '14 at 23:10
0

We've got constructors:

F , Super & Sub.

We've got objects f , super, & sub that are made using said constructors.

i.e. f = new F , super = new Super , sub = new Sub

We know f.__proto__ === super.__proto__ === Super.prototype from line 2

From line 3 we can see that sub.__proto__ === f & sub.__proto__.__proto__ === Super.prototype

Also we have Sub.superClass === Super.prototype from line 5.

and from line 4 & 6 we can say that sub.constructor === Sub & super.constructor === Super

The reason we can call new F before on line 3 before line 7 is because line 7 set's

f.__proto__.constructor === Super where as f.constructor is already Sub. basically line 7 is cleaning Super up and shouldn't effect Sub at all because you should never call .__proto__.constructor in real code.

This particular function explicity does not call Super as function but only make's sure that objects constructed through Sub have Super.prototype in their chain.

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • Actually on line 3 sub.__proto__ is foo, so says Chrome console... Which is the thing that troubles me.. – bliof Feb 02 '11 at 18:24
  • @bliof see [here](http://jsfiddle.net/Raynos/mKCPj/) All the assertions hold true like I said. – Raynos Feb 02 '11 at 18:39
  • @Raynos As far as I know when a property is searched for, it starts with the current object and if it is not there, it goes to the [[Prototype]] but here there is not a connection(or I cannot see one) between subClass's [[Prototype]] and the superClass. – bliof Feb 02 '11 at 18:45
  • @bliof `sup.__proto__.__proto__ === Super.prototype`. and `sub.__proto__ === Sub.prototype` There both in the chain – Raynos Feb 02 '11 at 18:50
  • @Raynos Super.prototype is the default Object, it is not the superClass, is it? – bliof Feb 02 '11 at 18:54
  • @bliof depends what's in Super.prototype. `extend(a,b)` then `Super.prototype === b.prototype` – Raynos Feb 02 '11 at 18:56
  • @Raynos And if b is function(){this.baz=10;} then it will be Object. But that means that if I want to access baz from an instance of a, it will search first a and then Object, and it will skip b. But this is not happening and it finds it. Why? – bliof Feb 02 '11 at 19:04
  • @bliof your using the function wrong. `b` is never called `b.prototype.baz` is accesible. the constructor `b` is never called so `this.baz = 10;` is never called. – Raynos Feb 02 '11 at 19:17
  • @Raynos Well it is called when I create an object. But I think that I understand what this function does. It allows me to access the properties created with the prototype property. And when I create the object the superclass.constructor.call(this); gives me access to the public properties in the superclass. 10x a lot. – bliof Feb 02 '11 at 19:37
0

As an alternative, you might consider the prototype javascript library. It includes inheritance.

Prototype Javascript Library

Here is an example from the prototype documentation.

var Animal = Class.create({
  initialize: function(name, sound) {
    this.name  = name;
    this.sound = sound;
  },

  speak: function() {
    alert(this.name + " says: " + this.sound + "!");
  }
});

// subclassing Animal
var Snake = Class.create(Animal, {
  initialize: function($super, name) {
    $super(name, 'hissssssssss');
  }
});

var ringneck = new Snake("Ringneck");
ringneck.speak();
//-> alerts "Ringneck says: hissssssssss!"

var rattlesnake = new Snake("Rattler");
rattlesnake.speak();
//-> alerts "Rattler says: hissssssssss!"

Here is the documentation page

bbrame
  • 18,031
  • 10
  • 35
  • 52