How to call a parent method from child class in javascript?

I've spent the last couple of hours trying to find a solution to my problem but it seems to be hopeless.

Basically I need to know how to call a parent method from a child class. All the stuff that I've tried so far ends up in either not working or over-writing the parent method.

I am using the following code to set up OOP in javascript:

// SET UP OOP
// surrogate constructor (empty function)
function surrogateCtor() {}

function extend(base, sub) {
    // copy the prototype from the base to setup inheritance
    surrogateCtor.prototype = base.prototype;
    sub.prototype = new surrogateCtor();
    sub.prototype.constructor = sub;
}

// parent class
function ParentObject(name) {
    this.name = name;
}
// parent's methods
ParentObject.prototype = {
    myMethod: function(arg) {
        this.name = arg;
    }
}

// child
function ChildObject(name) {
    // call the parent's constructor
    ParentObject.call(this, name);
    this.myMethod = function(arg) {
        // HOW DO I CALL THE PARENT METHOD HERE?
        // do stuff
    }
}

// setup the prototype chain
extend(ParentObject, ChildObject);

I need to call the parent's method first and then add some more stuff to it in the child class.

In most OOP languages that would be as simple as calling parent.myMethod() But I really cant grasp how its done in javascript.

Any help is much appreciated, thank you!


Solution 1:

Here's how its done: ParentClass.prototype.myMethod();

Or if you want to call it in the context of the current instance, you can do: ParentClass.prototype.myMethod.call(this)

Same goes for calling a parent method from child class with arguments: ParentClass.prototype.myMethod.call(this, arg1, arg2, ..) * Hint: use apply() instead of call() to pass arguments as an array.

Solution 2:

ES6 style allows you to use new features, such as super keyword. super keyword it's all about parent class context, when you are using ES6 classes syntax. As a very simple example, checkout:

Remember: We cannot invoke parent static methods via super keyword inside an instance method. Calling method should also be static.

Invocation of static method via instance method - TypeError !

class Foo {
  static classMethod() {
    return 'hello';
  }
}

class Bar extends Foo {
  classMethod() {
    return super.classMethod() + ', too';
  }
}
console.log(Bar.classMethod()); // 'hello' - Invokes inherited static method
console.log((new Bar()).classMethod()); // 'Uncaught TypeError' - Invokes on instance method

Invocation of static method via super - This works!

class Foo {
  static classMethod() {
    return 'hello';
  }
}

class Bar extends Foo {
  static classMethod() {
    return super.classMethod() + ', too';
  }
}

console.log(Bar.classMethod()); // 'hello, too'

Now super context changes based on invocation - Voila!

class Foo {
  static classMethod() {
    return 'hello i am static only';
  }

  classMethod() {
    return 'hello there i am an instance ';
  }
}

class Bar extends Foo {
  classMethod() {
    return super.classMethod() + ', too';
  }
}

console.log((new Bar()).classMethod()); // "hello there i am an instance , too"
console.log(Bar.classMethod()); // "hello i am static only"

Also, you can use super to call parent constructor:

class Foo {}

class Bar extends Foo {
    constructor(num) {
        let tmp = num * 2; // OK
        this.num = num; // ReferenceError
        super();
        this.num = num; // OK
    }
}

And of course you can use it to access parent class properties super.prop. So, use ES6 and be happy.

Solution 3:

Well in order to do this, you are not limited with the Class abstraction of ES6. Accessing the parent constructor's prototype methods is possible through the __proto__ property (I am pretty sure there will be fellow JS coders to complain that it's depreciated) which is depreciated but at the same time discovered that it is actually an essential tool for sub-classing needs (especially for the Array sub-classing needs though). So while the __proto__ property is still available in all major JS engines that i know, ES6 introduced the Object.getPrototypeOf() functionality on top of it. The super() tool in the Class abstraction is a syntactical sugar of this.

So in case you don't have access to the parent constructor's name and don't want to use the Class abstraction you may still do as follows;

function ChildObject(name) {
    // call the parent's constructor
    ParentObject.call(this, name);
    this.myMethod = function(arg) {
    //this.__proto__.__proto__.myMethod.call(this,arg);
    Object.getPrototypeOf(Object.getPrototypeOf(this)).myMethod.call(this,arg);
    }
}

Solution 4:

Here's a nice way for child objects to have access to parent properties and methods using JavaScript's prototype chain, and it's compatible with Internet Explorer. JavaScript searches the prototype chain for methods and we want the child’s prototype chain to looks like this:

Child instance -> Child’s prototype (with Child methods) -> Parent’s prototype (with Parent methods) -> Object prototype -> null

The child methods can also call shadowed parent methods, as shown at the three asterisks *** below.

Here’s how:

//Parent constructor
function ParentConstructor(firstName){
    //add parent properties:
    this.parentProperty = firstName;
}

//add 2 Parent methods:
ParentConstructor.prototype.parentMethod = function(argument){
    console.log(
            "Parent says: argument=" + argument +
            ", parentProperty=" + this.parentProperty +
            ", childProperty=" + this.childProperty
    );
};

ParentConstructor.prototype.commonMethod = function(argument){
    console.log("Hello from Parent! argument=" + argument);
};

//Child constructor    
function ChildConstructor(firstName, lastName){
    //first add parent's properties
    ParentConstructor.call(this, firstName);

    //now add child's properties:
    this.childProperty = lastName;
}

//insert Parent's methods into Child's prototype chain
var rCopyParentProto = Object.create(ParentConstructor.prototype);
rCopyParentProto.constructor = ChildConstructor;
ChildConstructor.prototype = rCopyParentProto;

//add 2 Child methods:
ChildConstructor.prototype.childMethod = function(argument){
    console.log(
            "Child says: argument=" + argument +
            ", parentProperty=" + this.parentProperty +
            ", childProperty=" + this.childProperty
    );
};

ChildConstructor.prototype.commonMethod = function(argument){
    console.log("Hello from Child! argument=" + argument);

    // *** call Parent's version of common method
    ParentConstructor.prototype.commonMethod(argument);
};

//create an instance of Child
var child_1 = new ChildConstructor('Albert', 'Einstein');

//call Child method
child_1.childMethod('do child method');

//call Parent method
child_1.parentMethod('do parent method');

//call common method
child_1.commonMethod('do common method');