Understanding prototypal inheritance in JavaScript - Part 3
tags: technical javascript
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
instanceofoperator 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 theisPrototypeOffunction 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
extendthis object with all the other objects that you wanted to derive fromComing 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 !