Why Prototypal Inheritance Matters

In notebook:
Article Notes
Created at:
2015-10-15
Updated:
2015-10-15
Tags:
Fundamentals JavaScript
Aadit M Shah | Why Prototypal Inheritance Matters
Argues that classical inheritance is not suitable for JavaScript
  • you cannot do ​var author = new Person.apply(null, ["Aadit", "Shah"]);​ – you cannot call ​apply​ on ​new​ constructor call
  • the ​new​ keyword was added to make appeal to Java developers
explains prototypal inheritance
​Object.create​ pattern

a nice pattern to simplify object creation and initialisation:
  var rectangle = {
    create  : function ( width, height ) {
        var self = Object.create( this );
        self.height = height;
        self.width = width;
        return self;
    }, 
    area : function () {
        return this.width * this.height;
    }
};

var rect = rectangle.create( 5, 10 );

alert( rect.area() );
compare this with the constructor pattern
  function Rectangle ( width, height ) {
    this.height = height;
    this.width = width;
}

Rectangle.prototype.area = function () {
    return this.width * this.height;
};

var rect = new Rectangle( 5, 10 );

alert( rect.area() );
the above object creation and initialisation pattern can be further abstracted with the ​extend​ implementation

A typical ​extend​ pattern in JS:
  Object.prototype.extend = function ( extension ) {
    var hasOwnProperty = Object.hasOwnProperty;
    var object = Object.create( this );
    for ( var property in extension )
        if ( hasOwnProperty.call( extension, property ) ||
                typeof object[ property ] === "undefined" )
            object[ property ] = extension[ property ];
    return object;
};
then the ​create​ method can be simplified to this:
  var rectangle = {
    create : function ( width, height ) {
        return this.extend( {
            height : height,
            width  : width
        } );
    },
    area   : function () {
        return this.width * this.height;
    }
};

var rect = rectangle.create( 5, 10 );

alert( rect.area() );
then explains the [[proto]] chain

Inheriting from multiple prototypes

need to extend ​extend​ to copy from multiple prototypes. You could just call ​extend​ (with the above implementation) several times on your object, modify to ​extend​ method to accept multiple parameters.

a basic pattern:
  Object.prototype.extend = function () {
    var hasOwnProperty = Object.hasOwnProperty;
    var object = Object.create( this );
    var length = arguments.length;
    var index = length;

    while ( index ) {
        var extension = arguments[ length - (index--) ];

        for ( var property in extension )
            if ( hasOwnProperty.call( extension, property ) ||
                    typeof object[ property ] === "undefined" )
                object[ property ] = extension[ property ];
    }

    return object;
};
​arguments​ is a standard JavaSciprt property that holds all the parameters passed to a function. In this case it holds several objects that we want to extend our object with.

shows an example where you can create an ​eventEmitter​ object and later extends the ​rectangle​ object with ​eventEmitter​ 
​​mixins
notes that ​eventEmitter​ doesn't (and shouldn't)​ have ​a ​create​ method. You don't want to create an object that only delegates to ​eventEmmitter​, second, it would override ​create​ method that already exists. These kinds of objects are called mixins. 
​​blueprints
define ​eventEmitter​ as a function rather than an object so you can have closures to store private variables.

it can have private variables (e.g. ​events​) and the methods are defined as ​this.on = function (event, listener){//...}​ 

then in your ​create​ function you can ​call​ this function to add the eventEmitter​ methods:
​create: function(){
  //...
  eventEmitter.call(self);
  // ...​ 

fixing the instanceof operator

many JavaScript programers prefer the constructor pattern since in this case the ​instanceof​ operator returns ​true​ 

this can be corrected by adding the ​Object.prototype.instanceof​ operator that uses ​Object.getProtoypeOf​ internally.