This post was originally published on Coding Glamour.

Inheritance in javascript blijf verdomd moeilijk, zoals ik deze week weer tegenkwam toen ik een vriend hielp in het porten van wat AS3 code naar javascript. Vandaar wat ready to use code snippets en een kleine uitleg om inheritance toe te passen.

Javascript kent een aantal manieren om code te mixen, maar ze zijn globaal onder te verdelen in inheritance en mixins. Inheritance is prettig voor een object structuur die je in een taal als Java of C# zou schrijven. Single inheritance van classes, als in Object->GameObject->Person->Enemy. Elk van de parent classes zou ook los kunnen bestaan, en de classes mogen zelf state bijhouden. Mixins hebben meer weg van abstracte classes, en zijn bedoeld om behavior te laten erven, sla er dus geen state in op want dan loop je tegen scoping issues aan. Je kunt meerdere mixin's in 1 object mixen voor multiple-inheritance-like behavior.

Inheritance
Allereerst lenen we wat code uit node.js. Omdat deze functie afhankelijk is van Object.create voegen we deze toe aan browsers die deze nog niet hebben middels een workaround van Ben Newman.

 Object.create = function (o) {
    if (arguments.length > 1) {
        throw new Error('Object.create implementation only accepts the first parameter.');
    }
    function F() {}
    F.prototype = o;
    return new F();
};
var inherits = function (ctor, superCtor) {
    ctor.super_ = superCtor;
    ctor.prototype = Object.create(superCtor.prototype);
    ctor.prototype.constructor = {
        value: ctor,
        enumerable: false
    };
};
Nu kunnen we een object hierarchie bouwen, waarin we een Parent en een Client hebben:

function Parent (initialValue) {
   this.list = [ initialValue ];
}
function Client (initialValue) {
    // apply with the second parameter the arguments for the parent ctor
    Parent.apply(this, [ initialValue ]);
}
inherits(Client, Parent);

Geen scoping problemen hier en instanceof werkt als verwacht:

var c = new Client(5);
var d = new Client(9);
c.list.push(3);
d.list.push(4);
console.log(c.list, d.list);
// geeft '[5, 3], [9, 4]'
console.log(d instanceof Parent);
// geeft true
console.log(d instanceof Client);
// geeft true


Mixins
Voor een mixin hoeven we geen code te lenen, maar kunnen we gewoon gaan typen. Neem twee simpele constructors:

function Person (name) {
    this.name = name;
}
function Product (name, price) {
    this.name = name;
    this.price = price;
}

De mixin hoeft niets te weten van de objecten die hem gaan importeren, het enige wat hij verwacht is dat er ergens een 'name' property op het object zit:

var greeter = function () {
    this.greet = function () {
        console.log("Hello", this.name);
    }
}

Nu kunnen we de 'greeter' in de twee types mixen en daarna aanroepen:

greeter.call(Person.prototype);
greeter.call(Product.prototype);
var person = new Person("jan");
var product = new Product("cloud9", 15.00);
person.greet();
// Hello jan
product.greet();
// Hello cloud9
// instanceof werkt niet op de mixin
console.log(person instanceof Person, person instanceof greeter);
// true, false

Code die je bijvoorbeeld in je types kan mixen zijn: logging functies en EventEmitter-achtige constructies.

Conclusie
Wil je state inheriten: inheritance. Wil je behavior inheriten: mixins.