102

Let's say you have the below code:

function A() {
    function modify() {
       x = 300;
       y = 400;
    }

    var c = new C();
}

function B() {
    function modify(){
       x = 3000;
       y = 4000;
    }

    var c = new C();
}

C = function () {
   var x = 10;
   var y = 20;

   function modify() {
      x = 30;
      y = 40;
   };

   modify();
   alert("The sum is: " + (x+y));
}

Now the question is, if there is any way in which I can override the method modify from C with the methods that are in A and B. In Java you would use the super-keyword, but how can you achieve something like this in JavaScript?

Mike
  • 14,010
  • 29
  • 101
  • 161
Daniel Nastase
  • 1,035
  • 2
  • 8
  • 6
  • 7
    `modify` is not a method but a nested function - there's a difference between those two... – Šime Vidas Jul 30 '11 at 19:13
  • 2
    In Java you use the `super` keyword to *access* the non-private fields and methods of a super-class. You don't use it to override them. – FK82 Jul 30 '11 at 21:07

7 Answers7

153

Edit: It's now six years since the original answer was written and a lot has changed!

  • If you're using a newer version of JavaScript, possibly compiled with a tool like Babel, you can use real classes.
  • If you're using the class-like component constructors provided by Angular or React, you'll want to look in the docs for that framework.
  • If you're using ES5 and making "fake" classes by hand using prototypes, the answer below is still as right as it ever was.

JavaScript inheritance looks a bit different from Java. Here is how the native JavaScript object system looks:

// Create a class
function Vehicle(color){
  this.color = color;
}

// Add an instance method
Vehicle.prototype.go = function(){
  return "Underway in " + this.color;
}

// Add a second class
function Car(color){
  this.color = color;
}

// And declare it is a subclass of the first
Car.prototype = new Vehicle();

// Override the instance method
Car.prototype.go = function(){
  return Vehicle.prototype.go.call(this) + " car"
}

// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"

var c = new Car("red");
c.go() // "Underway in red car"

Unfortunately this is a bit ugly and it does not include a very nice way to "super": you have to manually specify which parent classes' method you want to call. As a result, there are a variety of tools to make creating classes nicer. Try looking at Prototype.js, Backbone.js, or a similar library that includes a nicer syntax for doing OOP in js.

starball
  • 20,030
  • 7
  • 43
  • 238
Adam
  • 2,257
  • 1
  • 14
  • 8
  • 2
    Alternatively to using a tool to "make creating classes nicer" you could not make classes at all. Classical OO emulation in js always gets messy. – Raynos Jul 31 '11 at 11:24
  • 1
    (not constructive comment) for being the "low level" language in the browsers world is very ugly for no reason. Still learning it, thanks! – dnuske Nov 15 '12 at 17:05
  • 9
    I believe instead of Car.prototype = new Vehicle(); this should be Car.prototype = Object.create(Vehicle.prototype); no? – Jordan Dec 30 '14 at 17:57
  • @Martin is right, see [javascript-inheritance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance) – matoni May 02 '16 at 19:16
  • One of the reasons why Car.prototype = new Vehicle(); is incorrect because of having nothing to pass to Vehicle() while it receives a color. – Tushar Arora Jul 12 '16 at 06:55
  • ES5 isn't a "fake class." It used prototypal inheritance: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain https://javascript.info/prototype-inheritance This is how JS has been done for decades. – zedd45 Mar 24 '20 at 15:26
115

Since this is a top hit on Google, I'd like to give an updated answer.

Using ES6 classes makes inheritance and method overriding a lot easier:

'use strict';

class A {
    speak() {
        console.log("I'm A");
    }
}

class B extends A {
    speak() {
        super.speak();

        console.log("I'm B");
    }
}

var a = new A();
a.speak();
// Output:
// I'm A

var b = new B();
b.speak();
// Output:
// I'm A
// I'm B

The super keyword refers to the parent class when used in the inheriting class. Also, all methods on the parent class are bound to the instance of the child, so you don't have to write super.method.apply(this);.

As for compatibility: the ES6 compatibility table shows only the most recent versions of the major players support classes (mostly). V8 browsers have had them since January of this year (Chrome and Opera), and Firefox, using the SpiderMonkey JS engine, will see classes next month with their official Firefox 45 release. On the mobile side, Android still does not support this feature, while iOS 9, release five months ago, has partial support.

Fortunately, there is Babel, a JS library for re-compiling Harmony code into ES5 code. Classes, and a lot of other cool features in ES6 can make your Javascript code a lot more readable and maintainable.

Yotam Ofek
  • 2,300
  • 1
  • 18
  • 21
5

Once should avoid emulating classical OO and use prototypical OO instead. A nice utility library for prototypical OO is traits.

Rather then overwriting methods and setting up inheritance chains (one should always favour object composition over object inheritance) you should be bundling re-usable functions into traits and creating objects with those.

Live Example

var modifyA = {
    modify: function() {
        this.x = 300;
        this.y = 400;
    }
};

var modifyB = {
    modify: function() {
        this.x = 3000;
        this.y = 4000;
    }
};

C = function(trait) {
    var o = Object.create(Object.prototype, Trait(trait));

    o.modify();
    console.log("sum : " + (o.x + o.y));

    return o;
}

//C(modifyA);
C(modifyB);
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • 11
    You are not answering the question. This should be a comment if anything. – FK82 Jul 31 '11 at 07:25
  • @FK82 let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1998/discussion-between-raynos-and-fk82) – Raynos Jul 31 '11 at 13:06
3

modify() in your example is a private function, that won't be accessible from anywhere but within your A, B or C definition. You would need to declare it as

this.modify = function(){}

C has no reference to its parents, unless you pass it to C. If C is set up to inherit from A or B, it will inherit its public methods (not its private functions like you have modify() defined). Once C inherits methods from its parent, you can override the inherited methods.

Alex Heyd
  • 1,323
  • 1
  • 10
  • 17
2

the method modify() that you called in the last is called in global context if you want to override modify() you first have to inherit A or B.

Maybe you're trying to do this:

In this case C inherits A

function A() {
    this.modify = function() {
        alert("in A");
    }
}

function B() {
    this.modify = function() {
        alert("in B");
    }
}

C = function() {
    this.modify = function() {
        alert("in C");
    };

    C.prototype.modify(); // you can call this method where you need to call modify of the parent class
}

C.prototype = new A();
Mario Zigliotto
  • 8,315
  • 7
  • 52
  • 71
lovesh
  • 5,235
  • 9
  • 62
  • 93
  • 1
    `C.prototype.modify()` would have the wrong `this` value. Namely `C.prototype` instead of the instance of c. Please use `.call(this)` but then your answer is just a duplicate :) – Raynos Jul 31 '11 at 12:33
1

Not unless you make all variables "public", i.e. make them members of the Function either directly or through the prototype property.

var C = function( ) {
    this.x = 10 , this.y = 20 ;
    this.modify = function( ) {
        this.x = 30 , this.y = 40 ;
        console.log("(!) C >> " + (this.x + this.y) ) ;
    } ;
} ;

var A = function( ) {
    this.modify = function( ) {
       this.x = 300 , this.y = 400 ;
       console.log("(!) A >> " + (this.x + this.y) ) ;
    } ;
} ;
    A.prototype = new C ;

var B = function( ) {
    this.modify = function( ) {
       this.x = 3000 , this.y = 4000 ;
       console.log("(!) B >> " + (this.x + this.y) ) ;
    } ;
} ;


new C( ).modify( ) ;
new A( ).modify( ) ;
new B( ).modify( ) ; 

You will notice a few changes.

Most importantly the call to the supposed "super-classes" constructor is now implicit within this line:

<name>.prototype = new C ;

Both A and B will now have individually modifiable members x and y which would not be the case if we would have written ... = C instead.

Then, x, y and modify are all "public" members so that assigning a different Function to them

 <name>.prototype.modify = function( ) { /* ... */ }

will "override" the original Function by that name.

Lastly, the call to modify cannot be done in the Function declaration because the implicit call to the "super-class" would then be executed again when we set the supposed "super-class" to the prototype property of the supposed "sub-classes".

But well, this is more or less how you would do this kind of thing in JavaScript.

HTH,

FK

FK82
  • 4,907
  • 4
  • 29
  • 42
  • There is no point in the `.prototype = new C;` your shadowing all the members of the prototype anyway – Raynos Jul 31 '11 at 11:21
  • @Raynos: Yes there is. To wit, all the inheriting `Objects` would be sharing the same member in `C` if you do not instantiate a `C` Object. Thus, changing `x` in `A` would change `x` in `C` and thus change `x` in `B`. Which is obviously undesireable. – FK82 Jul 31 '11 at 12:13
  • you missed the point. You can remove the line and the code would still function – Raynos Jul 31 '11 at 12:20
  • @Raynos: You are missing your own point I'm afraid. ;-) We want `A` and `B` to inherit from `C`. If that line would be missing, that would not be the case. In fact the only prototype both `A` as well as `B` would "shadow" would have access to in that case would be `Object.prototype`. – FK82 Jul 31 '11 at 12:27
  • look at the code. A and B do not use any of the members of C up the prototype. So "inheriting" from C is useless. This is because A and B redefine `x`,`y` and `modify` and thus shadow all of `C`'s members. What's the point of putting C in the prototype if your not using it? It's dead code. – Raynos Jul 31 '11 at 12:31
  • @Raynos: This is a contrived and abstract example. I'm assuming that in a particular case `C` would have members to be inherited by `A` and `B`. Otherwise this would not be a problem pertaining to inheritance anyhow. – FK82 Jul 31 '11 at 12:41
0

function A() {
    var c = new C();
 c.modify = function(){
  c.x = 123;
  c.y = 333;
 }
 c.sum();
}

function B() {
    var c = new C();
 c.modify = function(){
  c.x = 999;
  c.y = 333;
 }
 c.sum();
}


C = function () {
   this.x = 10;
   this.y = 20;

   this.modify = function() {
      this.x = 30;
      this.y = 40;
   };
   
   this.sum = function(){
 this.modify();
 console.log("The sum is: " + (this.x+this.y));
   }
}

A();
B();