Click here to Skip to main content
Licence CPOL
First Posted 9 Feb 2008
Views 14,231
Bookmarked 11 times

True inheritence with plain-old JavaScript

By | 24 Aug 2010 | Article
This article describes a technique for making use of inheritence with JavaScript, including inheriting interface, implementation, and data from base classes.

An Example of Using True Inheritance with Plain JavaScript

This article describes a technique for using inheritance with JavaScript, including inheriting interfaces, implementations, and data from base classes. In this example, there's a base Animal class that has a data member called lifespan. Animal has a virtual function called getSpeechText() which should return a message that a particular animal will say when it is asked to talk. The generic Animal class just says that it can't talk. Derived classes should override and return some text such as "bow wow" for dogs or "meow" for cats. The Animal class also has a non-virtual function called talk() which simply calls getSpeechText() to get the text and then displays it to the console. The lifespan field is initialized to a default value of 100. It is a public data member that any derived class can access and provide an initial value for (to change the default 100 set by the base).

  1. The getSpeechText() method illustrates interface inheritance, where derived classes can override the behavior of a base class.
  2. The talk() method illustrates implementation inheritance, where derived classes can simply inherit functionality from the base class (no override).
  3. The lifespan data member illustrates data inheritance, where the derived classes inherit data referenced by a base class.

The example below will illustrate these features in C++ and JavaScript.

This example creates two classes derived from Animal, called Dog and Human. Both override the getSpeechText() method. Only the Dog class changes the lifespan data member (to 15). The Human class uses the default 100 as initialized in the base class.

The technique is to use the fact that the prototype property of a user-defined class can be changed to point to an object. Therefore, if we point the prototype property of a derived class to a new instance of the base class, then the chain of responsibility will include this instance. This way, a member of the base class may be accessed via an instance of the derived class if the derived class doesn't have the same member defined.

I used JScript with WSH (Windows Scripting Host), but the same stuff works with Netscape's and all other versions of JavaScript. (Note: To test with Netscape's JavaScript without the browser, obtain jsshell.exe from mozilla.org. This is a shell that executes JavaScript files. The built-in "print" statement in this shell lets you output data to 'standard out'. If you have WSH installed on your machine, you can run the JavaScript version by placing the source in an Animal.js file and then double-clicking on it. To compile the C++ version with Visual C++ installed, use the following command to create Animal.exe:

cl Animal.cpp -GX

Animal.cpp

#include <iostream>

class Animal
{
public:
    Animal()
    {
        lifespan = 100;
    }

    void talk()
    {
        std::cout << getSpeechText() << std::endl;
    }

    virtual const char* getSpeechText()
    {
        return "Generic Animal doesn't talk";
    }

    int lifespan;
};

class Dog : public Animal
{
public:
    Dog()
    {
        lifespan = 15;
    }

    virtual const char* getSpeechText()
    {
        return "Bow wow";
    }
};

class Human : public Animal
{
public:
    virtual const char* getSpeechText()
    {
        return "Hi there";
    }
};

void main()
{
    Dog d;
    std::cout << "Dog's lifespan: ";
    std::cout << d.lifespan;
    std::cout << " and talks by saying: ";
    std::cout << std::endl;

    d.talk();

    Human h;
    std::cout << "Human's lifespan: ";
    std::cout << h.lifespan;
    std::cout << " and talks by saying: ";
    std::cout << std::endl;

    h.talk();
}

Animal.js

function Animal_getSpeechText()
{
    return "Generic Animal doesn't talk"
}

function Animal_talk()
{
    WScript.Echo( this.getSpeechText() )
}

function Animal()
{
    this.lifespan = 100
    this.talk = Animal_talk
    this.getSpeechText = Animal_getSpeechText
}

function Dog_getSpeechText()
{
    return "Bow wow"
}

function Dog()
{
    this.lifespan = 15
    this.getSpeechText = Dog_getSpeechText
}
Dog.prototype = new Animal

function Human_getSpeechText()
{
    return "Hi there"
}

function Human()
{
    this.getSpeechText = Human_getSpeechText
}
Human.prototype = new Animal

function main()
{
    var d = new Dog
    WScript.Echo( "Dog's lifespan: " + d.lifespan + 
                  " and talks by saying:" )

    d.talk()

    var h = new Human
    WScript.Echo( "Human's lifespan: " + h.lifespan + 
                  " and talks by saying:" )
    h.talk()
}

main()

Output

The output from both samples should look something like this:

Dog's lifespan: 15 and talks by saying:
Bow wow
Human's lifespan: 100 and talks by saying:
Hi there

Calling Base Constructors with Arguments

You can also call the constructor of the base class from the constructor of the derived class, as in C++, by assigning the base class constructor to some arbitrary method name of the derived class (such as "base") and then calling that method on the "this" object in the constructor of the derived class. This is necessary if you want to propagate constructor arguments passed to the derived class constructor to the base class constructor. In C++, you do this by specifying the base class name in the member initialization list of the constructor of the derived class.

In the above sample, if both the Animal and Dog classes took the lifespan value as a parameter in their constructor, then the constructor for the Dog class would need to pass the argument to the constructor of its base class, the Animal class. The modified form of Dog's constructor would look like this:

C++

class Dog : public Animal
{
public:
    Dog( int lifespan )
    :    Animal( lifespan )
    {
    }

...

JavaScript

function Dog( lifespan )
{
    this.base = Animal
    this.base( lifespan )

    ...
}

History

  • 9th February, 2008: Initial post
  • 23rd August, 2010: Article updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Kenneth Kasajian

Other

United States United States

Member

Follow on Twitter Follow on Twitter
My interests mostly revolve around making machines do work for people. I'm a computer programmer, software architect, development manager and program manager. I started my career creating software for abstract art, followed by work in embedded systems and HMI. In the 90s I created a successful product called Visual DLL and helped develop the Sales Force Automation product, Arsenal. I've often been involved in online communities, creating games, utilities, and collaboration software. Currently I'm a Program Manager, where I get to tell others what needs to get done. Smile | :)

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalnamespacing PinmemberdotnetCarpenter4:47 12 Feb '08  
GeneralImproved Version PinmemberSchaeferFFM7:12 10 Feb '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120517.1 | Last Updated 24 Aug 2010
Article Copyright 2008 by Kenneth Kasajian
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid