3

I'm trying to extend class B to class A, and class A to class Super, using the function apply. The following code works OK:

function Super() {
    this.talk = function () {
        alert("Hello");
    };
}

function A() {
    // instance of A inherits Super
    Super.apply(this);
}

function B() {
    // instance of B inherits A
    A.apply(this);
}

var x = new B();
x.talk(); // Hello

But what if I want to class A inherits from class Super, not just its instances? I tried this:

function Super() {
    this.talk = function () {
        alert("Hello, I'm the class");
    };

    // function of the class' instance?
    this.prototype.talk = function () {
        alert("Hello, I'm the object");
    };
}

function A() {
    // nothing here
}

// A inherits from Super, not its instance
Super.apply(A);


function B() {
    // instance of B inherits A
    A.apply(this);
}

A.talk(); // static function works!

var x = new B();
x.talk(); // but this doesn't...

Am I doing something wrong?

3
  • Does it work if you move the talk function outside of Super and specify it like: Super.prototype.talk = function() { // Stuff }? Commented Sep 23, 2013 at 13:55
  • @EmilH It doesn't. Chrome says the same: "Uncaught TypeError: Object #<B> has no method 'talk'" Commented Sep 23, 2013 at 13:59
  • Add B.prototype = Object.create(A.prototype); after declaring function B and above A.talk(); and it should work. This is explained below in detail. Commented Sep 23, 2013 at 19:13

2 Answers 2

4
function Super() { }

// Static method, called by Super.talk()
Super.talk = function () {
    alert("Hello, I'm the class");
};

// Prototype method, should be called by instance
Super.prototype.talk = function () {
    alert("Hello, I'm the object");
};

function A() {
    // 'override' purposes
    Super.apply(this, arguments);
    // ..
}

// A inherits from Super
A.prototype = Object.create(Super.prototype);
A.prototype.constructor = A;

function B() { 
    A.apply(this, arguments);
}

// B inherits from A
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

// A.talk() won't work, of course.

var x = new B();
x.talk();
Sign up to request clarification or add additional context in comments.

4 Comments

Great answer! But I'd rather use Object.create(Super.prototype) instead of new Super() and add constructor method: A.prototype.constructor = A.
Shouldn't you also add Super.call(this) into A() body or parent constructor will be called anyway via new?
@Pavlo Super.call(this) is not required in A() body because there are no properties declared in Super's constructor to inherit they are only added to prototype in above case, so setting prototype is sufficient.
In general, what Pavlo says is important because otherwise the data that was intended to be instance data in Super will appear as "static", i.e. "class" data in the derived classes. They'll get shadowed anyway after calling Super.apply(this) but still you don't want that data hanging around in the "class".
1

There are two ways you can add public properties and methods to your class (rather function class) :

Method 1 of adding public property, added to each instance:

function MyClass(){
      this.publicProperty = 'public property'; 
}

Method 2 of adding public property, added to prototype, common for all instances:

MyClass.prototype.publicMethod = function(){
      console.log('public method');
}

When you want to inherit from a Class you need to inherit all the public properties and methods.

Inheriting properties and methods added using method 1:

function MyDerivedClass(){
      MyClass.apply(this);
}

Inheriting properties and methods added using method 2:

MyDerivedClass.prototype = Object.create(MyClass.prototype);

So in your case when you do Super.apply(A);, your are actually adding talk method to prototype of A (Using method 2 via 1). But B inherits from A only the properties using method 1. Just add below line after declaring B function:

B.prototype = Object.create(A.prototype);

And things will work as you expect. Hope this is helpful.

2 Comments

Worth noting: In this situation MyDerivedClass.prototype = Object.create(MyClass.prototype);, you can pass the arguments to the MyClass constructor in Object.create: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - However, it is unclear how one would get the args from instantiation of MyDerivedClass to MyClass.
@netpoetica I did not consider the arguments inside the constructor functions coz the question did not have. Please take a look at this to know how you would pass on the arguments while instantiating.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.