Understanding prototypal inheritance in JavaScript - Part 3

In the previous installment of the prototypal inheritance series we have seen how to instantiate new objects based on a prototype object, now let's see how to make a derived object to extend the functionality of the prorotype object.

As we have seen in the first installment of the series, in a class-based object system, if we want to extend the functionality of a class, we make a derived class, and add new functions, or override existing ones.

In JavaScript we take our prototype object, create a new object based on it, and extend it like this:

var PSprite = Object.create(PRect);
$.extend(PSprite, {
    init: function (options) {
        // Initialize the base object
        PRect.init.call(this, options);

        // Initialize the object
    },

    setAnimation: function (options) {
        // Set the sprite animation
    }
});

The first important thing to notice here is that for the first step we use the same Object.create function that we used last time to create a new instance, so in a prototypal object system there is no difference between instantiating an object and making a derived object.

The other thing to notice is that I used jQuery to extend the object. That's because the JavaScript language is constantly evolving, and only in very recent times it got a function that extends objects, called Object.assign. The problem with this function is that almost no browser supports it, as it is too new. Fortunately, many libraries (including jQuery, friGame, Underscore.js/Lo-Dash) implement an extend function that copies all the properties of an object to another object.

The third thing to notice is that the init function has been overridden, so the overridden function must be explicitly called.

Lastly, as the name suggests, the PSprite object is also a Prototype Object, so we can create a Maker function for it:

var Sprite = friGame.Maker(PSprite);

and use this Maker Function as we saw last time:

var my_sprite = Sprite({left: 10, top: 10});
my_sprite.setAnimation({animation: 'player'});

With the techniques described in these posts it should be more clear how to migrate from a class-based object system to a prototypal one.

Before concluding this post let's quickly address a couple of issues:

  • The instanceof operator cannot be used to know if an object is derived from a Prototype Object. As the JavaScript language is dynamically typed, I prefer to use Duck typing instead of restricting functions to use only certain specific types, but if you really want to know whether an object is derived from a Prototype Object, you can use the isPrototypeOf function like this:

    if (PRect.isPrototypeOf(my_sprite)) { // true
    }
    
  • Multiple inheritance cannot be done, but if you rely on Duck typing, you can derive from an object, and then extend this object with all the other objects that you wanted to derive from

  • Coming from a Python background, I have no problem in making all the object methods and attributes public, the interface and implementation can be separated using coding conventions, comments, and clear communication between team members, without needing the language to enforce public and private data, but if you really want to have private data while still using the prototypal object system, as Eric Elliott pointed out in the comments of the previous post (thank you!), there exists a library called Stampit that does that and much more.

In the next blog post we will conclude this series by exploring some advanced/dangerous aspects, stay tuned.

Comments !