Click here to Skip to main content
6,594,932 members and growing! (16,356 online)
Email Password   helpLost your password?
Web Development » Client side scripting » General License: The Code Project Open License (CPOL)

True inheritence with plain-old JavaScript

By Kenneth Kasajian

This article describes a technique for making use of inheritence with JavaScript, including inheriting interface, implementation and data from base classes
Javascript, CSS, HTML, ASP, ASP.NET, Ajax
Posted:9 Feb 2008
Views:7,542
Bookmarked:4 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
4 votes for this article.
Popularity: 2.45 Rating: 4.08 out of 5

1

2
1 vote, 25.0%
3
1 vote, 25.0%
4
2 votes, 50.0%
5

An example of using true inheritence with plain JavaScript.

This article describes a technique for making use of inheritence with JavaScript, including inheriting interface, implementation 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 getSpeachText() 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 getSpeachText() 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 inital value for (to change the default 100 set by the base).

  1. The getSpeachText() method illustrates interface inheritence, where derived classes can override the behavior of a base class.
  2. The talk() method illustrates implementation inheritence, where derived classes can simply inhert functionaly from the base class (no override.)
  3. The lifespan data member illustrates data inheritence, where the derive 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 getSpeachText() 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 one points 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 << getSpeachText() << std::endl;
    }

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

    int lifespan;
};

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

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

class Human : public Animal
{
public:
    virtual const char* getSpeachText()
    {
        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_getSpeachText()
{
    return "Generic Animal doesn't talk"
}

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

function Animal()
{
    this.lifespan = 100
    this.talk = Animal_talk
    this.getSpeachText = Animal_getSpeachText
}


function Dog_getSpeachText()
{
    return "Bow wow"
}

function Dog()
{
    this.lifespan = 15
    this.getSpeachText = Dog_getSpeachText
}
Dog.prototype = new Animal


function Human_getSpeachText()
{
    return "Hi there"
}

function Human()
{
    this.getSpeachText = Human_getSpeachText
}
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 the base class constructor to some arbitrary method name of the derive 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 propage constructor arguments passed to the drived 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 a 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 )

    ...
}

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


Member

Occupation: Other
Location: United States United States

Other popular Client side scripting articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh)FirstPrevNext
Generalnamespacing PinmemberdotnetCarpenter5:47 12 Feb '08  
GeneralImproved Version PinmemberSchaeferFFM8:12 10 Feb '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 9 Feb 2008
Editor:
Copyright 2008 by Kenneth Kasajian
Everything else Copyright © CodeProject, 1999-2009
Web16 | Advertise on the Code Project