Inheritance in JavaScript – A Cool Way

So, JavaScript is a strange language. This prototyping stuff is new for everyone coming from another ecosystem. But it’s not so complex. There are many libraries that provide extending ‘class‘ methods that mimic extending from more conventional languages, like Java for example. (Example of such method is Ember’s Ember.Object.extend)

Now I’m going to show you how to write such an inheritance method in JavaScript and how to use it. In the meantime we will see how prototyping works.

Let’s begin.

First of all we will define a helper method used to copy the properties from one object to another, overriding the common ones:


function ex (destination, source) {
  var p;

  for (p in source) {
    if (source.hasOwnProperty(p)) {
      destination[p] = source[p];
    }
  }
  return destination;
}

Here we just copy the own properties (not the inherited/prototype ones) from the source object to the destination object. Read more about hasOwnProperty here.

Let’s define our main extending method:


function extend (data, staticData) {
  var parent = this, // 1
      child = function () { // 2
        if (data.initialize) { // 2.1
          data.initialize.apply(this, arguments);
        } else { // 2.2
          parent.apply(this, arguments);
        }
      };

  ex(child, parent); // 3
    
  if (staticData) { // 4
    ex(child, staticData);
  }

  if (!data) { // 5
    data = {};
  }

  child.prototype = ex(Object.create(parent.prototype), data); // 6
  child.prototype.constructor = child; // 7
  child.prototype.__super = parent.prototype; // 8

  return child; // 9
}

The idea is that this method is called on the class to become parent class (you will see in the next example what I am talking about).
It has two parameters – data and staticData.
The data parameter is used to pass instance fields and methods to the child class that may override parent ones.
The staticData is used to define class level fields and methods to the child class.
Let’s see what we are doing:

  1. The parent class is this – the caller of the method.
  2. The child class is defined with a new constructor.
    2.1. If we pass an ‘initialize‘ method as field of the data parameter it is used for the       initialization. So in our inheritance ‘initialize‘ is the constructor method.
    2.2. If not we call the parent’s constructor as super constructor.
  3. We use the previously defined ‘ex‘ function to copy all the parent’s static methods/fields in the child – this includes the ‘extend‘ method as well, so the child can become a parent class too.
  4. If we passed staticData, we copy it to the child class – that way we can override some of the previously copied parent static methods/fields.
  5. If we didn’t pass ‘data‘ parameter assign to it default value – the empty object.
  6. Now it is time for the instance methods and fields – create the child prototype, using the parent’s prototype modified with the passed data.
  7. Set the constructor to the child’s prototype.
  8. Set a pointer to the parent’s prototype – a __super.
  9. OK, the child class is ready – return it.

What are we really doing?
First of all, classes in JavaScript are defined using functions – constructors. Every function can be a constructor. If you call the function preceding it with the new keyword, it creates an instance.
In the constructor, when called with ‘new‘, ‘this‘ points to the instance to be created – so if we define fields or methods on ‘this‘ they become instance ones.

When we have an instance and we call method or read field and it is not found in ‘this‘, it is searched in the prototype object of the constructor of the instance.
So if we define methods or fields in the object, pointed by the prototype field of the constructor function – they become instance ones too.

That’s why copying the parent prototype into the child’s is basically extending the parent into the child.

That’s all – I’m doing all of this in the ‘extend‘ method. Let’s use it!


function Foo (a, b) {//1
  this.a = a;
  this.b = b;
}

Foo.prototype.c = function () {//2
  return this.a + this.b
};

var foo = new Foo(2, 5);//3
console.log(foo.c());//4
  1. We create a new function (class); We assign the passed ‘a‘ and ‘b‘ parameters to this.
  2. We are adding a new instance function ‘c‘ (In the prototype of Foo). It calculates the sum of ‘this.a‘ and ‘this.b‘.
  3. We create a new instance!
  4. The result will be 2+5=7

Now is time for the inheritance!


Foo.extend = extend; //1

Bar = Foo.extend({ //2
  initialize: function (a, b, d) {
    this.__super.constructor(a, b);
    this.d = d;
  },    
  d: 8,
  e: function () {
    return this.a + this.b + this.d;
  }
});

var bar = new Bar(3, 1, 9); //3
console.log(bar.c(), bar.e()); //4
  1. We set the ‘extend‘ function to Foo. Now Foo can be parent class!
  2. We extend Foo passing data with:
    – ‘initialize‘ method (remember – this is your constructor), that calls the super constructor (Foo) with the passed ‘a‘ and ‘b‘ parameters and sets ‘d‘ in ‘this‘.
    – ‘d’ – a new instance field.
    – ‘e‘ – a new instance method, calculating the sum of ‘this.a‘, ‘this.b‘ and ‘this.c‘.
  3. Let’s create a new Bar instance!
  4. We’ll see 3+1=4 and 3+1+9=13

So we have a child class now? Very similar to Ruby or Java isn’t it. We can extend Bar too, it has the ‘extend‘ method inherited from Foo. You can try that in this jsfiddle.

OK that’s it.

Useful Links:

  1. MDN  Javascript – https://developer.mozilla.org/en/docs/Web/JavaScript
  2. Ideas in coder wall – https://coderwall.com/p/ajugeq
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s