139

Is it possible to call the base method from a prototype method in JavaScript if it's been overridden?

MyClass = function(name){
    this.name = name;
    this.do = function() {
        //do somthing 
    }
};

MyClass.prototype.do = function() {  
    if (this.name === 'something') {
        //do something new
    } else {
        //CALL BASE METHOD
    }
};
Foreever
  • 7,099
  • 8
  • 53
  • 55
Mark Clancy
  • 7,831
  • 8
  • 43
  • 49

14 Answers14

209

I did not understand what exactly you're trying to do, but normally implementing object-specific behaviour is done along these lines:

function MyClass(name) {
    this.name = name;
}

MyClass.prototype.doStuff = function() {
    // generic behaviour
}

var myObj = new MyClass('foo');

var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
    // do specialised stuff
    // how to call the generic implementation:
    MyClass.prototype.doStuff.call(this /*, args...*/);
}
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • 1
    I don't get this, i came here exactly for the same purpose as markvpc . I mean, i want to have a kind of a "private" method which is used from other methods in the prototype. Your response forces me to create a factory and i'd like to know if there's any way to avoid that. – R01010010 Dec 24 '14 at 03:09
  • 11
    Do not use "Class" words in JS because it creates confusion. There is not classes in JavaScript – Polaris Jan 09 '15 at 13:58
  • 1
    This only works for objects instantiated. What if you want to override all instances? – supertonsky Mar 26 '15 at 10:33
  • Works for me! Exactly what I needed. I have 4 constructors that inherit from a parent. Two of them need to override and call a method on the base constructor that is their prototype. This allowed me to exactly that. – binarygiant Jul 09 '15 at 16:45
  • 3
    I don't understand why this has so many upvotes and is marked as correct. This only overrides the behavior for one instance of the base-class, not all instances of the sub-class. Thus this does not answer the question. – BlueRaja - Danny Pflughoeft Aug 11 '15 at 21:21
  • Indeed this IS an answer for the original question, as it shows how to call the prototype's implementation with the context (i.e. variable this) set to the derived "instance" (i.e. myObjSpecial) – Semanino Nov 12 '15 at 17:09
  • @BlueRaja: What you criticise is how myObjSpecial is created - in Christoph's answer this is done inline in the code. Of course you could write a factory function which uses an "instance" of MyClass as prototype for the objects it builds. But, using NEW IS A REAL BAD PATTERN and deprecated by every professional JS developer I know. Use factory functions which do a inst = Object.create( prototype ) – Semanino Nov 12 '15 at 17:16
25

Well one way to do it would be saving the base method and then calling it from the overriden method, like so

MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){  

    if (this.name === 'something'){

        //do something new

    }else{
        return this._do_base();
    }

};
Ramuns Usovs
  • 1,474
  • 11
  • 10
  • 11
    This will create infinite recursion. – Johan Tidén Sep 21 '12 at 11:34
  • 3
    I've been there: Infinite recursion. – jperelli Nov 28 '13 at 18:31
  • The else clause is calling and running _do_base, which is a reference to prototype.do. Since no parameters (or state) have changed, the code will again go into the else, calling _do_base again. – Johan Tidén May 08 '15 at 08:45
  • 10
    @JohanTidén the `_do_base` stores a reference to whatever function was defined before. If there was none, then it’d be `undefined`. JavaScript is not `make`—expressions are never lazily evaluated like you suggest they are. Now, if the prototype being inherited from *also* used _do_base to store what it thinks is its base type’s implementation of `do`, then you do have a problem. So, yeah, a closure would be a better, inheritance-safe way to store the reference to the original function implementation if using this method—though that would require using `Function.prototype.call(this)`. – binki May 08 '15 at 17:27
17

I'm afraid your example does not work the way you think. This part:

this.do = function(){ /*do something*/ };

overwrites the definition of

MyClass.prototype.do = function(){ /*do something else*/ };

Since the newly created object already has a "do" property, it does not look up the prototypal chain.

The classical form of inheritance in Javascript is awkard, and hard to grasp. I would suggest using Douglas Crockfords simple inheritance pattern instead. Like this:

function my_class(name) {
    return {
        name: name,
        do: function () { /* do something */ }
    };
}

function my_child(name) {
    var me = my_class(name);
    var base_do = me.do;
    me.do = function () {
        if (this.name === 'something'){
            //do something new
        } else {
            base_do.call(me);
        }
    }
    return me;
}

var o = my_child("something");
o.do(); // does something new

var u = my_child("something else");
u.do(); // uses base function

In my opinion a much clearer way of handling objects, constructors and inheritance in javascript. You can read more in Crockfords Javascript: The good parts.

Magnar
  • 28,550
  • 8
  • 60
  • 65
  • 3
    Very nice indeed, but you can't really call `base_do` as a function, because you lose any `this` binding in the original `do` method that way. So, the setup of the base method is a bit more complex, especially if you want to call it using the base object as `this` instead of the child object. I would suggest something akin to `base_do.apply(me, arguments)`. – Giulio Piancastelli Nov 04 '14 at 10:16
  • Just wondering, why don’t you use `var` for `base_do`? Is this on purpose and, if so, why? And, as @GiulioPiancastelli said, does this break `this` binding within `base_do()` or will that call inherit the `this` from its caller? – binki May 08 '15 at 17:40
  • @binki I updated the example. The `var` should be there. Using `call` (or `apply`) allows us to bind `this` properly. – Magnar May 08 '15 at 23:44
11

I know this post is from 4 years ago, but because of my C# background I was looking for a way to call the base class without having to specify the class name but rather obtain it by a property on the subclass. So my only change to Christoph's answer would be

From this:

MyClass.prototype.doStuff.call(this /*, args...*/);

To this:

this.constructor.prototype.doStuff.call(this /*, args...*/);
Community
  • 1
  • 1
Philip Holly
  • 713
  • 7
  • 18
  • 6
    Don't do this, `this.constructor` might not always point to `MyClass`. – Bergi Jul 31 '14 at 14:11
  • Well, it should, unless someone screwed up setting up the inheritance. 'this' should always refer to the top-level object, and its 'constructor' property should always point to its own constructor function. – Triynko Feb 23 '17 at 17:08
6

if you define a function like this (using OOP)

function Person(){};
Person.prototype.say = function(message){
   console.log(message);
}

there is two ways to call a prototype function: 1) make an instance and call the object function:

var person = new Person();
person.say('hello!');

and the other way is... 2) is calling the function directly from the prototype:

Person.prototype.say('hello there!');
Alejandro Silva
  • 8,808
  • 1
  • 35
  • 29
5

This solution uses Object.getPrototypeOf

TestA is super that has getName

TestB is a child that overrides getName but, also has getBothNames that calls the super version of getName as well as the child version

function TestA() {
  this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
  this.count = 2;
  return ' TestA.prototype.getName is called  **';
};

function TestB() {
  this.idx = 30;
  this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
  return ' TestB.prototype.getName is called ** ';
};

TestB.prototype.getBothNames = function tb_gbn() {
  return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};

var tb = new TestB();
console.log(tb.getBothNames());
SymbolixAU
  • 25,502
  • 4
  • 67
  • 139
4
function NewClass() {
    var self = this;
    BaseClass.call(self);          // Set base class

    var baseModify = self.modify;  // Get base function
    self.modify = function () {
        // Override code here
        baseModify();
    };
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Berezh
  • 942
  • 9
  • 12
4

An alternative :

// shape 
var shape = function(type){
    this.type = type;
}   
shape.prototype.display = function(){
    console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){ 
    // call implementation of the super class
    this.__proto__.display.apply(this,arguments);
}
Anum Malik
  • 554
  • 1
  • 7
  • 11
  • Despite it may work, I won't recommend this solution. There are many reasons why using [`__proto__`](https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) (which changes the [[Prototype]]` of an object) should be avoided. Please use the [`Object.create(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) route instead. – KarelG Dec 30 '16 at 09:13
2

If I understand correctly, you want Base functionality to always be performed, while a piece of it should be left to implementations.

You might get helped by the 'template method' design pattern.

Base = function() {}
Base.prototype.do = function() { 
    // .. prologue code
    this.impldo(); 
    // epilogue code 
}
// note: no impldo implementation for Base!

derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }
xtofl
  • 40,723
  • 12
  • 105
  • 192
1

If you know your super class by name, you can do something like this:

function Base() {
}

Base.prototype.foo = function() {
  console.log('called foo in Base');
}

function Sub() {
}

Sub.prototype = new Base();

Sub.prototype.foo = function() {
  console.log('called foo in Sub');
  Base.prototype.foo.call(this);
}

var base = new Base();
base.foo();

var sub = new Sub();
sub.foo();

This will print

called foo in Base
called foo in Sub
called foo in Base

as expected.

Michael
  • 1,416
  • 1
  • 9
  • 21
1

Another way with ES5 is to explicitely traverse the prototype chain using Object.getPrototypeOf(this)

const speaker = {
  speak: () => console.log('the speaker has spoken')
}

const announcingSpeaker = Object.create(speaker, {
  speak: {
    value: function() {
      console.log('Attention please!')
      Object.getPrototypeOf(this).speak()
    }
  }
})

announcingSpeaker.speak()
Max Fichtelmann
  • 3,366
  • 1
  • 22
  • 27
0

In addition, if you want to override all instances and not just that one special instance, this one might help.

function MyClass() {}

MyClass.prototype.myMethod = function() {
  alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
  MyClass.prototype.myMethod_original.call( this );
  alert( "doing override");
};

myObj = new MyClass();
myObj.myMethod();

result:

doing original
doing override
supertonsky
  • 2,563
  • 6
  • 38
  • 68
0
function MyClass() {}

MyClass.prototype.myMethod = function() {
  alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
  MyClass.prototype.myMethod_original.call( this );
  alert( "doing override");
};

myObj = new MyClass();
myObj.myMethod();
0

No, you would need to give the do function in the constructor and the do function in the prototype different names.

ChrisInCambo
  • 8,455
  • 15
  • 50
  • 63