Javascript’s prototypal inheritance, for a C# developer

The oth­er day I put up a post with some quick bul­let points about objects in javascript to help some­one from a sta­t­ic, strong­ly typed lan­guage (like C# or Java) back­ground under­stand javascript’s dynam­ic and loose type sys­tem. One impor­tant thing I haven’t talked about yet is the way inher­i­tance work in javascript, which again, is very dif­fer­ent from those found in C# or Java.

Most object ori­ent­ed lan­guages like C# and Java use class­es to define types, which are basi­cal­ly blue­prints for cre­at­ing objects, this approach to inher­i­tance is referred to as clas­si­cal inher­i­tance. Javascript on the oth­er hand, has no class­es, instead objects inher­it from oth­er objects, this approach is referred to as pro­to­typ­al inher­i­tance.

Constructor functions

You can use func­tions, which them­selves are objects to act as con­struc­tors and pro­vide blue­prints for cre­at­ing objects:

function Person(name, age) {
    // properties
    this.Name = name;
    this.Age = age;

    // methods
    this.sayHello = function () {
        return "Hello, my name is " + this.Name + "!";
    }
}

This cre­ates a new object Person.prototype, which all new Per­son objects will inher­it from. You can then use the new oper­a­tor to cre­ate a new Per­son object using this con­struc­tor:

var person = new Person("John", 10);

The per­son object inher­its all the mem­bers (prop­er­ties and func­tions) that are defined by the con­struc­tor func­tion above, as can be seen in Chrome’s debug­ger (CTRL+SHIFT+J):

image

Dynamically modifying the prototype

It is pos­si­ble to make changes to Person.prototype object out­side of its con­struc­tor func­tion, to add a say­Bye func­tion to the Person.prototype object:

Person.prototype.sayBye = function (recipient) {
    return "Good bye, " + recipient + "!";
}

Once defined, this new func­tion will be avail­able on all Per­son objects, even if they were cre­at­ed pri­or to the new func­tion:

var goodbyeMsg = person.sayBye("Yan"); // returns "Good bye, Yan!"

Understanding how members are looked up

This is all the code we have writ­ten so far:

function Person(name, age) {
    // properties
    this.Name = name;
    this.Age = age;

    // methods
    this.sayHello = function () {
        return "Hello, my name is " + this.Name + "!";
    }
}

var person = new Person("John", 10);

Person.prototype.sayBye = function (recipient) {
    return "Good bye, " + recipient + "!";
};

var goodbyeMsg = person.sayBye("Yan"); // returns "Good bye, Yan!"

If you run the code to the end, you will see the say­Bye func­tion we added at the end of the exam­ple:

image

It falls under the per­son object’s __proto__ mem­ber rather than on the object itself (as is the case for the con­struc­tor defined mem­bers – Name, Age and the say­Hel­lo func­tion) but it’ll still be acces­si­ble direct­ly on the per­son object.

When access­ing a mem­ber on an object, Javascript will check in that object first, if the mem­ber is not found it will then fol­lows the inher­i­tance chain until either the mem­ber is found or it will return unde­fined if it has exhaust­ed all the objects on the inher­i­tance chain.

In order for javascript to keep track of this chain and fig­ure out where next to look for a mem­ber, an inter­nal prop­er­ty __proto__ is used to point to the next object in the chain. Because every object is ulti­mate­ly inher­it­ed from Object, it’ll be at the top of every object’s inher­i­tance chain and the last object you’ll be able to fetch if you con­tin­u­ous­ly invoke the __proto__ mem­ber before you get unde­fined returned:

myObj.__proto__.__proto__….

Extending objects

Nor­mal­ly to extend an object you need to per­form a two step process:

1. Invoke the base con­struc­tor

function Employee(name, age, salary) {
    // equivalent to calling base(name, age) in C#
    // this invokes the base class's constructor on the current object
    Person.call(this, name, age);

    // new property and method
    this.Salary = salary;
    this.reportSalary = function () {
        return "Hi, my name is " + this.Name + ", my salary is " + this.Salary + ".";
    }
}

As you can see, this invokes the Per­son con­struc­tor func­tion (see above) on the cur­rent object, if you try to cre­ate a new object using this con­struc­tor:

var employee = new Employee("Jane", 20, 12000);

this is what the object looks like:

image

Notice any­thing miss­ing? What hap­pened to the say­Bye func­tion we added to the Per­son object out­side of its con­struc­tor?

Well, because the say­Bye func­tion is not defined in the Per­son object’s con­struc­tor func­tion and all we’ve done so far is to invoke that func­tion to set up some prop­er­ties and func­tions for a new Employ­ee object so of course it won’t include any­thing that’s dynam­i­cal­ly added to the object out­side of its con­struc­tor func­tion.

2. Set up the inher­i­tance rela­tion­ship

This sec­ond step is sim­ple but cru­cial, this is how you set up the ‘rela­tion­ship’ between the Per­son and Employ­ee objects:

// make Employee inherit from Person
Employee.prototype = new Person();

Doing this tells Javascript to use Per­son as the pro­to­type for Employ­ee, i.e. pro­to­typ­al inheritance’s way of say­ing using Per­son as super­class to Employ­ee. Now that you’ve done this step, if you try to cre­ate a new Employ­ee object now this is what your object looks like:

var employee = new Employee("Jane", 20, 12000);

image

Checking an object’s inheritance chain

You can check if an object appear in anoth­er object’s inher­i­tance chain using the isPro­to­type­Of func­tion. For exam­ple, using the Per­son and Employ­ee con­struc­tor func­tions (remem­ber, they are objects) defined above:

var person = new Person("John", 10);
var employee = new Employee("Jane", 20, 10000);

Employee.prototype.isPrototypeOf(person); // false
Person.prototype.isPrototypeOf(person); // true
Object.prototype.isPrototypeOf(person); // true

Employee.prototype.isPrototypeOf(employee); // true
Person.prototype.isPrototypeOf(employee); // true
Object.prototype.isPrototypeOf(employee); // true

Where the inheritance technique fails

Whilst the method of extend­ing an object above works it does have an implic­it require­ment for the par­ent object’s con­struc­tor func­tion to allow a para­me­ter­less con­struc­tor to work, which can be a prob­lem in cer­tain sit­u­a­tions.

For instance, if the Per­son object’s con­struc­tor explic­it­ly requires the para­me­ters name and age to be spec­i­fied:

function Person(name, age) {
    if (!name || !age) {
        throw new Error("A person must have a name and age");
    }

    // properties
    this.Name = name;
    this.Age = age;

    // methods
    this.sayHello = function () {
        return "Hello, my name is " + this.Name + "!";
    }
}

In sit­u­a­tions like this, this line will except:

Employee.prototype = new Person(); // Uncaught Error: A person must have a name and age

Other inheritance techniques

Besides the tech­nique I men­tioned above, here are two oth­er ways to cre­ate object inher­i­tance for your ref­er­ence.

Dou­glas Crockford’s ini­tial­ize tech­nique

In Dou­glas Crockford’s post here he wrote about a dif­fer­ent tech­nique on ini­tial­iz­ing objects, in his last update in 2008 this is his pre­ferred method:

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() { }
        F.prototype = o;
        return new F();
    };
}

and to use it, sup­pose we have already cre­at­ed an Employ­ee object called employ­ee, to cre­ate anoth­er just like it:

var employee2 = Object.create(employee);

This tech­nique is more about cloning an exist­ing object, employee2 will there­fore inher­it all of employ­ee’s cur­rent state:

image

MooTools

MooTools is a mod­u­lar Object-Ori­ent­ed Javascript frame­work, it includes a Class con­struc­tor func­tion which includes some nice fea­tures such as:

  • Extends – allows you to spec­i­fy a base class which to extend from
  • Imple­ments – allows you to spec­i­fy one or more class­es to adopt prop­er­ties from (think imple­ment­ing an inter­face)

So using MooTools, this is how you can cre­ate the Per­son and Employ­ee class­es:

// create a new Person class
var Person = new Class({
    initialize: function (name, age) {
        // properties
        this.Name = name;
        this.Age = age;

        // methods
        this.sayHello = function () {
            return "Hello, my name is " + this.Name + "!";
        }
    }
});

// add the sayBye function to the Person class
Person.implement({
    sayBye: function (recipient) {
        return "Good bye, " + recipient + "!";
    }
});

// create a new Employee class which inherits from the Person class
var Employee = new Class({
    Extends: Person,
    initialize: function (name, age, salary) {
        this.parent(name, age); // calls initialize method of Person class
        this.Salary = salary;

        // new property and method
        this.Salary = salary;
        this.reportSalary = function () {
            return "Hi, my name is " + this.Name + ", my salary is " + this.Salary + ".";
        }
    }
});

var person = new Person("John", 10);
var employee = new Employee("Jane", 20, 12000);

This is how the per­son and employ­ee objects look in the Chrome Debug­ger:

image

References:

Dou­glas Crock­ford on Pro­to­typ­al Inher­i­tance

MooTools Class exam­ples