38

I have a "SuperClass" with "info" as an instance variable. "SuperClass" has function "printInfo()". "printInfo()" needs to access instance variable "info". I want to create a "SubClass" which also has method "printInfo()". I want to call printInfo() of "SuperClass" from "printInfo()" of "SubClass".

SuperClass = function()
{
    this.info = "I am superclass";
    console.log("SuperClass:");
};

SuperClass.prototype.printInfo = function(that)
{
    console.log("printing from superclass printInfo");
    console.log(that.info);
};

SubClass = function(){};

SubClass.prototype = new SuperClass();

SubClass.prototype.printInfo = function()
{
    console.log("calling superclass");
    this.constructor.prototype.printInfo(this);
    console.log("called superclass");
};

var sc = new SubClass();
sc.printInfo();

You can see that I am passing "that" as a parameter to printInfo. Without "that" parameter, "info" is printed as "undefined". Like in the following case, "this.info" is undefined when this function is called from object of "SubClass".

SuperClass.prototype.printInfo = function()
    {
        console.log("printing from superclass printInfo");
        console.log(this.info);
    };

What is the proper way to override and invoke methods of superclass in javascript, enabling functions to access instance variables of the class?

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
coolscitist
  • 3,317
  • 8
  • 42
  • 59
  • possible duplicate of [Javascript Class Inheritance For Functions](http://stackoverflow.com/questions/16963111/javascript-class-inheritance-for-functions) – Bergi Apr 15 '14 at 07:57
  • and you should also [get your constructor inheritance correct](http://stackoverflow.com/questions/10898786/correct-javascript-inheritance/) – Bergi Apr 15 '14 at 07:58

7 Answers7

30

You are messing with the SubClass's prototype with the SuperClass's object, in this line

SubClass.prototype = new SuperClass();

the child's prototype should depend on the Parent's prototype. So, you can inherit like this

SubClass.prototype = Object.create(SuperClass.prototype);

Also, it is quite normal to change the constructor to the actual function, like this

SubClass.prototype.constructor = SubClass;

To keep your implementation generic, you can use Object.getPrototypeOf, to get the parent prototype in the inheritance chain and then invoke printInfo, like this

SubClass.prototype.printInfo = function() {
    Object.getPrototypeOf(SubClass.prototype).printInfo(this);
};

Since, info is defined in the SubClass yet, it will print undefined. You might also want to call the parent't constructor, like this

var SubClass = function() {
    SuperClass.call(this);
};

Note: You are creating global variables, by omitting var keyword before SuperClass and SubClass.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 1
    To keep it generic, I called super constructor with Object.getPrototypeOf(Subclass.prototype).constructor.call(this). That is same way you invoke the super class function. Although I am not sure if this is the correct way, I am no expert on how js works. – Gökhan Barış Aker Feb 27 '15 at 18:02
  • 2
    Wouldn't the call from `Subclass.printInfo()` to `Superclass.printInfo()` be `Object.getPrototypeOf(SubClass.prototype).printInfo.call(this)` rather than just `...printInfo(this)?` I ask because I tried it your way and got an error about `undefined`. I'm not a JS expert, so it's not clear to me why either way would work or not work. – SaganRitual Nov 15 '16 at 13:58
  • @thefourtheye If you wanna be really clean you could say `Object.getPrototypeOf(Object.getPrototypeOf(this))`. – Aristotle Pagaltzis Jul 15 '18 at 14:17
  • @GreatBigBore Correct. You need `.call(this)` so that `this` inside the called method will be the same as inside the calling method. – Aristotle Pagaltzis Jul 15 '18 at 14:18
11
class Thing {
  constructor(age) { this.age = age; }
  die(how) { console.log(`Died of ${how}`); }
}

class Me extends Thing {
  constructor() { super(59); console.log(`I am ${this.age}`); }
  // Refer to a method from the superclass that is overridden in the subclass
  die(how) { super.die('liver failure'); console.log(`while ${how}`) }
}

(new Me()).die('hang gliding');
Denis Howe
  • 2,092
  • 1
  • 23
  • 25
10

After reading all the answers, I am using the following inheritance mechanism:

var SuperClass = function()
{
    this.info = "I am superclass";
    console.log("SuperClass:");
};

SuperClass.prototype.printInfo = function()
{
    console.log("printing from superclass printInfo");
    console.log("printinfo");
    console.log(this.info);
};

var SubClass = function(){
    SuperClass.call(this);
};

SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;

SubClass.prototype.printInfo = function()
{
    console.log("calling superclass");
    Object.getPrototypeOf(SubClass.prototype).printInfo.call(this);
    console.log("called superclass");
};

var sc = new SubClass();
sc.printInfo();
Aristotle Pagaltzis
  • 112,955
  • 23
  • 98
  • 97
coolscitist
  • 3,317
  • 8
  • 42
  • 59
7

You can write it like this :

SuperClass.prototype.printInfo = function(){
  console.log("printing from superclass printInfo");
  console.log(this.info); 
};

SubClass.prototype.printInfo = function(){
  console.log("calling superclass");
  SuperClass.prototype.printInfo.call(this);
  console.log("called superclass");
};
Camille Wintz
  • 951
  • 7
  • 8
5

For anybody who comes more from a Java world I would ignore all of the above and use the following syntax instead that was introduced in 2015

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

class Square extends Polygon {
  constructor(sideLength) {
    super(sideLength, sideLength);
  }
  get area() {
    return this.height * this.width;
  }
  set sideLength(newLength) {
    this.height = newLength;
    this.width = newLength;
  }
} 

More info on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

And suddently u can use super as keyword to access ancester etc.... For me finding this was a big relief

TomFree
  • 1,091
  • 3
  • 17
  • 31
2

@coolscitist

Instead of

SubClass.prototype.printInfo = function()
{
    Object.getPrototypeOf(SubClass.prototype).printInfo.call(this);
};

use this

SubClass.prototype.printInfo = function()
{
    Object.getPrototypeOf(this.constructor.prototype).printInfo.call(this);
};
Lo HaBuyshan
  • 359
  • 2
  • 12
  • 1
    Thanks. Only your solution worked for me. The other answers called the superclass method ok, but got undefined 'this' error. – yoshi Feb 24 '16 at 02:54
  • 3
    No, this is not ok. Let say a new class `Class3` inherit from `SubClass`, calling `Class3`'s printInfo() will cause infinite loop. This is because the `this.constructor` above will always give `Class3` instead of `SubClass`, i.e. calling printInfo function of `Class3`'s superclass (SubClass) again & again. – Johnny Wong Jun 13 '16 at 06:53
0

The only way I've been able to sort this out is to save the parent's function in different variable before overriding in the child class definition.

var Foo = function(){
    var self = this.
    this.init = function(a,b){
        self.a = a;
        seld.b = b;
    };
}

var Goo = function(){
    Foo.apply(this);
    var self = this;
    self.Foo = { init: self.init };//saves the super class's definition of init in a new variable
    self.init = function(a,b,c){
       self.Foo.init(a,b);//can call the super class function
       self.c = c;
    };
}

var a = new Foo();
a.init(1,2);
var b = new Goo();
b.init(1,2,3);
Dallas Clarke
  • 261
  • 2
  • 5