Simple inheritance with JavaScript - Eternal Coding - HTML5 / Windows / Kinect / 3D development - Site Home - MSDN Blogs

Simple inheritance with JavaScript


 

Simple inheritance with JavaScript

  • Comments 19

A lot of my friends are C# or C++ developers. They are used to use inheritance in their projects and when they want to learn or discover JavaScript, one of the first question they ask is: “But how can I do inheritance with JavaScript?”.

Actually, JavaScript uses a different approach than C# or C++ to create an object oriented language. It is a prototype-based language. The concept of prototyping implies that behavior can be reused by cloning existing objects that serve as prototypes. Every object in JavaScript depends from a prototype which defines a set of functions and members that the object can use. There is no class. Just objects. Every object can then be used as prototype for another object.

This concept is extremely flexible and we can use it to simulate some concepts from OOP like inheritance.

Implementing inheritance

Let’s image we want to create this hierarchy using JavaScript:

image

First of all, we can create ClassA easily. Because there is no explicit classes, we can define a set of behavior (A class so…) by just creating a function like this:

var ClassA = function() {
    this.name = "class A";
}

This “class” can be instantiated using the new keyword:

var a = new ClassA();
ClassA.prototype.print = function() {
    console.log(this.name);
}

And to use it using our object:

a.print();

Fairly simple, right?

The complete sample is just 8 lines long:

var ClassA = function() {
    this.name = "class A";
}

ClassA.prototype.print = function() {
    console.log(this.name);
}

var a = new ClassA();

a.print();

Now let’s add a tool to create “inheritance” between classes. This tool will just have to do one single thing: Cloning the prototype:

var inheritsFrom = function (child, parent) {
    child.prototype = Object.create(parent.prototype);
};

This is exactly where the magic happens! By cloning the prototype, we transfer all members and functions to the new class.

So if we want to add a second class that will be child of the first one, we just have to use this code:

var ClassB = function() {
    this.name = "class B";
    this.surname = "I'm the child";
}

inheritsFrom(ClassB, ClassA);

Then because ClassB inherited the print function from ClassA, the following code is working:

var b = new ClassB();
b.print();

And produces the following output:

class B

We can even override the print function for ClassB:

ClassB.prototype.print = function() {
    ClassA.prototype.print.call(this);
    console.log(this.surname);
}

In this case, the produced output will look lie this:

class B
I’m the child

The trick here is to call ClassA.prototype to get the base print function. Then thanks to call function we can call the base function on the current object (this).

Creating ClassC is now obvious:

var ClassC = function () {
    this.name = "class C";
    this.surname = "I'm the grandchild";
}

inheritsFrom(ClassC, ClassB);

ClassC.prototype.foo = function() {
    // Do some funky stuff here...
}

ClassC.prototype.print = function () {
    ClassB.prototype.print.call(this);
    console.log("Sounds like this is working!");
}

var c = new ClassC();
c.print();

And the output is:

class C
I’m the grandchild

Sounds like this is working!

Philosophy…

To conclude, I just want to clearly state that JavaScript is not C# or C++. It has its own philosophy. If you are a C++ or C# developer and you really want to embrace the full power of JavaScript, the best tip I can give you is: Do not try to replicate your language into JavaScript. There is no best or worst language. Just different philosophies!

Leave a Comment
  • Please add 6 and 3 and type the answer here:
  • Post
  • The above implementation of inheritsFrom works for the basic prototype chain, but it doesn't set the constructor property on the child prototype like the 'new' operator would, which can cause bugs in some circumstances. Here's a version that does:

    var inheritsFrom = function (child, parent) {

       child.prototype = Object.create(parent.prototype);

       child.prototype.constructor = child;

    };

  • I agree. I tried to remain really simple for this first step. Thank you very much for completing it btw:)

  • "Every object in JavaScript contains a prototype (this.prototype) which defines a set of functions and members that the object can use."

    Instances don't have a `prototype` member, constructor functions do. `this.prototype` is not valid, unless `this` is referencing the constructor itself and not an instance. Instances do have a reference to their constructor, which in turn has a reference to its prototype.

    jsbin.com/.../edit

  • Absolutely right. I fixed my wording. Thank you for your feedback!

  • Shouldn't be the output for c.print() be:

    class C

    I'm the grandchild

    Sounds like this is working!

  • Oups :)

  • sasasasa

  • Also important to note that JavaScript only supports single inheritance.

  • This is not true:

    "Because all objects in JavaScript are mutable, you can add more functions later on the root prototype. These functions won’t be propagated to the child."

    You can check it here: jsbin.com/.../edit

  • Very simple article — for beginners. But thank you, was nice read :)

  • >> Because all objects in JavaScript are mutable, you can add more functions later on the root prototype. These functions won’t be propagated to the child.

    It's wrong! See example:

    var a = function() {

    this.foo = 'abc';

    }

    var b = function() {}

    b.prototype = new a();

    var c = new b();

    a.prototype.baz = 123;

    c.baz; // => 123

  • The first question you should ask these people is why they want to do it.  Javascript is its own language, with its own rhythms and styles; copying the styles from plain OO languages is to perhaps miss some of the power of Javascript, which is as much a functional language as it is an OO one.

    Now with that out of the way this bit is wrong:

    "However, the inheritance is static. We clone the prototype at certain point in time. Because all objects in JavaScript are mutable, you can add more functions later on the root prototype. These functions won’t be propagated to the child."

    In fact it's horribly wrong.  Keep this person away from small children and junior developers wrong.

    Just add the following after your code,and you'll see that prototypal inheritance is anything but static:

       ClassA.prototype.sing = function(lyric) {

           console.log(lyric + " doowop");

       };

       a.sing("Well, hello Dolly"); //=> "Well, hello Dolly doowop"

       b.sing("Excuse me, while I kiss the sky"); //=>"Excuse me, while I kiss the sky doowop"

  • @Surtich,  Gorbenko Oleg  and Scott D Sauyet:

    You are right guys and I have to apologize here. I did a first version where alongside prototype cloning, I went as well through all non-prototyped properties and functions of the parent class (everything declared directly on ClassA and not on ClassA.prototype) and duplicated it manually. Then I changed my mind to get back to something simpler but because I'm lazy I forgot to read back my article.

    By the way thank you so much guys for your comments, I really appreciate!

  • have a problem with the whole idea of OOP in JavaScript. The problem is, JavaScript is not an OOP language in its core. It can be shaped and molded to look and behave like an OOP language, but in essence, it's a Prototype based, function as first citizen, scripting language, similar to IO. So, when you force it to work and behave like an OOP language, you end up having awkward code like the samples above. There are several different programming language paradigms other than OOP that fit very well for different purposes and in some cases, for certain problems, they work much better than OOP.

    So, in my humble opinion, when writing a program in a language like JavaScript, we need to ask ourselfves, what is the benefit we're trying to get by trying to mimic OOP featurs like class inheritence and intefraces, etc. Are we doing these for an actual added benefit, or we're doing it just for the sake of doing it?

  • Nice write up

Page 1 of 2 (19 items) 12