0

OK, I've revised most of the techniques to implement inheritance in JavaScript OOP. As a Java programmer, I'm interested in the classical approach but here's the problem; say I want to create the Animal class (I know it's not a real class, but let me use this term) like this:

function Animal(name){  
    this.name = name;
}
Animal.prototype.getName = function() {
    return this.name;
}

It is important to note that this is a concrete class in my first intention, I want to instantiate it, not just use it as a superclass. I may create several Animal instances, each one with its own name.

A possible way to extend this class is to do the following:

function Cat(name, owner) {
    this.name = name;
    this.owner = owner;
}
// ALTERNATIVE 1:
    Cat.prototype = Object.create(Animal.prototype);
// ALTERNATIVE 2: 
    Cat.prototype = new Animal('LOLA');
// END OF ALTERNATIVES
Cat.constructor.prototype = Cat;
Cat.prototype.jump = function() {
    alert(this.name + " jumping");
}

With the ALTERNATIVE 1 we just inherit the methods of the superclass, in fact we need to redefine the name property in the Cat. With the ALTERNATIVE 2 nothing actually changes, we just have one more object in the chain that holds a name property that's quite useless: it's the same for all the Cat instances.

The point here is that I've written the Animal class with its own name and I just throw it away as soon as I extend it. What I'd like to have though is a way to inherit both properties and methods and, most of all, I'd like to be able to reuse the Animal constructor.

s.susini
  • 601
  • 1
  • 9
  • 18
  • http://stackoverflow.com/a/1598077/251311 – zerkms Aug 14 '13 at 00:54
  • 4
    If some alien civilization ever digs up the Stack Overflow database, they will think that JavaScript was exclusively used for classifying animals. – Šime Vidas Aug 14 '13 at 00:55
  • 1
    In the Cat function body you usually call `Animal.call(this,name);` to take instance properties from Animal. Some more on basic constructor functions in JS (using animals again): http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Aug 14 '13 at 00:59

1 Answers1

0

The traditional way to inherit the properties of the base constructor is as follows:

function Cat(name, owner) {
    Animal.call(this, name); // call the base constructor
    this.owner = owner;
}

Cat.prototype = new Animal;
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
    alert(this.name + " jumping");
};

The above code is equivalent to the following class in other languages:

class Cat extends Animal {
    constructor(name, owner) {
        super(name);
        this.owner = owner;
    }

    jump() {
        alert(this.name + " jumping");
    }
}

The new way to inherit properties is exactly the same, save that we replace new Animal with Object.create(Animal.prototype). The reason we prefer the new way is because:

  1. Calling new Animal is unnecessary overhead. The Cat constructor calls it again anyway.
  2. Calling new Animal might not return a blank object. It might add some properties to the object.
  3. We don't know what arguments to call new Animal with yet. Hence it makes no sense to call it.

Thus the preferred way of inheritance is now:

function Cat(name, owner) {
    Animal.call(this, name); // call the base constructor
    this.owner = owner;
}

Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.jump = function () {
    alert(this.name + " jumping");
};

Note that it's important to call the base constructor because it may do some initialization which is necessary for the instance to work properly.

If you're interested in writing JavaScript code in a classical style then take a look at the following answer which describes prototype-class isomorphism. The following code it taken from the above answer:

function CLASS(prototype, base) {
    switch (typeof base) {
    case "function": base = base.prototype;
    case "object": prototype = Object.create(base, descriptorOf(prototype));
    }

    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

function descriptorOf(object) {
    return Object.keys(object).reduce(function (descriptor, key) {
        descriptor[key] = Object.getOwnPropertyDescriptor(object, key);
        return descriptor;
    }, {});
}

Using the CLASS function we can define pseudo-classes in JavaScript as follows:

var Animal = CLASS({
    constructor: function (name) {
        this.name = name;
    },
    getName: function () {
        return this.name;
    }
});

var Cat = CLASS({
    constructor: function (name, owner) {
        Animal.call(this, name);
        this.owner = owner;
    },
    jump: function () {
        alert(this.name + " jumping");
    }
}, Animal);

There are other ways to do inheritance in JavaScript as well. I suggest you read my blog post on Why Prototypal Inheritance Matters to understand more about inheritance in JavaScript.

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299