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

JavascriptOopMethodsParent

Javascript Problem Overview


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!

Javascript Solutions


Solution 1 - Javascript

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 2 - Javascript

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 3 - Javascript

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 - Javascript

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');

Solution 5 - Javascript

In case of multiple inheritance level, this function can be used as a super() method in other languages. Here is a demo fiddle, with some tests, you can use it like this, inside your method use : call_base(this, 'method_name', arguments);

It make use of quite recent ES functions, an compatibility with older browsers is not guarantee. Tested in IE11, FF29, CH35.

/**
 * Call super method of the given object and method.
 * This function create a temporary variable called "_call_base_reference",
 * to inspect whole inheritance linage. It will be deleted at the end of inspection.
 *
 * Usage : Inside your method use call_base(this, 'method_name', arguments);
 *
 * @param {object} object The owner object of the method and inheritance linage
 * @param {string} method The name of the super method to find.
 * @param {array} args The calls arguments, basically use the "arguments" special variable.
 * @returns {*} The data returned from the super method.
 */
function call_base(object, method, args) {
    // We get base object, first time it will be passed object,
    // but in case of multiple inheritance, it will be instance of parent objects.
    var base = object.hasOwnProperty('_call_base_reference') ? object._call_base_reference : object,
    // We get matching method, from current object,
    // this is a reference to define super method.
            object_current_method = base[method],
    // Temp object wo receive method definition.
            descriptor = null,
    // We define super function after founding current position.
            is_super = false,
    // Contain output data.
            output = null;
    while (base !== undefined) {
        // Get method info
        descriptor = Object.getOwnPropertyDescriptor(base, method);
        if (descriptor !== undefined) {
            // We search for current object method to define inherited part of chain.
            if (descriptor.value === object_current_method) {
                // Further loops will be considered as inherited function.
                is_super = true;
            }
            // We already have found current object method.
            else if (is_super === true) {
                // We need to pass original object to apply() as first argument,
                // this allow to keep original instance definition along all method
                // inheritance. But we also need to save reference to "base" who
                // contain parent class, it will be used into this function startup
                // to begin at the right chain position.
                object._call_base_reference = base;
                // Apply super method.
                output = descriptor.value.apply(object, args);
                // Property have been used into super function if another
                // call_base() is launched. Reference is not useful anymore.
                delete object._call_base_reference;
                // Job is done.
                return output;
            }
        }
        // Iterate to the next parent inherited.
        base = Object.getPrototypeOf(base);
    }
}

Solution 6 - Javascript

How about something based on Douglas Crockford idea:

    function Shape(){}

    Shape.prototype.name = 'Shape';

    Shape.prototype.toString = function(){
        return this.constructor.parent
            ? this.constructor.parent.toString() + ',' + this.name
            : this.name;
    };


    function TwoDShape(){}

    var F = function(){};

    F.prototype = Shape.prototype;

    TwoDShape.prototype = new F();

    TwoDShape.prototype.constructor = TwoDShape;

    TwoDShape.parent = Shape.prototype;

    TwoDShape.prototype.name = '2D Shape';
    

    var my = new TwoDShape();

    console.log(my.toString()); ===> Shape,2D Shape

Solution 7 - Javascript

There is a much easier and more compact solution for multilevel prototype lookup, but it requires Proxy support. Usage: SUPER(<instance>).<method>(<args>), for example, assuming two classes A and B extends A with method m: SUPER(new B).m().

function SUPER(instance) {
    return new Proxy(instance, {
        get(target, prop) {
            return Object.getPrototypeOf(Object.getPrototypeOf(target))[prop].bind(target);
        }
    });
}

Solution 8 - Javascript

more flexible answer with classic js.

You define "_parent = A.prototype;" in the child class, then you can call parent's methods with apply:

class A{
	_msg='A';
	_msgOnlyA=' great from A';
	constructor(){
	}
	hello(){
		console.log('hello '+this._msg+', '+this._msgOnlyA);
	}
};
class B extends A{
	_parent = A.prototype;
	_msg='B';
	constructor(){
		super();
	}
	hello(){
		this._parent.hello.apply(this, arguments);
		console.log('hello '+this._msg);
	}
};
var b = new B();
b.hello();

Solution 9 - Javascript

While you can call the parent method by the prototype of the parent, you will need to pass the current child instance for using call, apply, or bind method. The bind method will create a new function so I doesn't recommend that if you care for performance except it only called once.

As an alternative you can replace the child method and put the parent method on the instance while calling the original child method.

function proxy(context, parent){
  var proto = parent.prototype;
  var list = Object.getOwnPropertyNames(proto);
  
  for(var i=0; i < list.length; i++){
    var key = list[i];

    // Create only when child have similar method name
    if(context[key] !== proto[key]){
      let currentMethod = context[key];
      let parentMethod = proto[key];
      
      context[key] = function(){
        context.super = parentMethod;
        return currentMethod.apply(context, arguments);
      }
    }
  }
}

// ========= The usage would be like this ==========

class Parent {
  first = "Home";

  constructor(){
    console.log('Parent created');
  }

  add(arg){
    return this.first + ", Parent "+arg;
  }
}

class Child extends Parent{
  constructor(b){
    super();
    proxy(this, Parent);
    console.log('Child created');
  }

  // Comment this to call method from parent only
  add(arg){
    return super.add(arg) + ", Child "+arg;
  }
}

var family = new Child();
console.log(family.add('B'));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYemSalatView Question on Stackoverflow
Solution 1 - JavascriptDmytro MedvidView Answer on Stackoverflow
Solution 2 - JavascriptYemSalatView Answer on Stackoverflow
Solution 3 - JavascriptReduView Answer on Stackoverflow
Solution 4 - JavascriptCaptureWizView Answer on Stackoverflow
Solution 5 - JavascriptweegerView Answer on Stackoverflow
Solution 6 - JavascriptAessandroView Answer on Stackoverflow
Solution 7 - JavascriptZzZomboView Answer on Stackoverflow
Solution 8 - JavascriptgezdyView Answer on Stackoverflow
Solution 9 - JavascriptStefansAryaView Answer on Stackoverflow