#Demiurgejs: 3 types of Javascript inheritance

Demiurge

I’ve jumped into the rabbit hole and have been digging through the various types of inheritance possible in JavaScript.
Not really original, I know, but in a project I’m working on I needed to mix various types of inheritance, so I created a small utility lib to help doing just this: let objects inherit members from another object.

Source

The lib’s called demiurge and can be found in the demiurge github repository.

It’s based on a gist I created a few days ago and already tweeted about, it can be found here.

API

There are only 3 methods of interest for setting up inheritance in JavaScript:

  • Classical inheritance:
    demiurge.extend( TargetClass, SourceClass )
  • Object augmentation:
    demiurge.decorate( target, SourceClass )
  • Prototypal inheritance:
    demiurge.createObject( object )

Usage

You can link directly to the lib in my project page:

<script type="text/javascript" src="http://creynders.github.com/demiurge/bin/demiurge-1.0.0.min.js"></script>

Be sure to use the correct version number, at the time of writing 1.0.0

Classical inheritance

In classical inheritance we want to let a class inherit another classes members. (I know there are no classes in JavaScript, but you know what I mean.)

Example

We create 2 classes:

//
var Base = function(){
    this.something = 'something';
};
Base.prototype = {
    getSomething : function(){
        return this.something;
    }
};

var Foo = function(){
    Foo.__super__.call( this ); //call super constructor
    this.bar = 'bar';
};
demiurge.extend( Foo, Base ); //classical inheritance
Foo.prototype.getBar = function(){
    return this.bar;
};

var foo = new Foo();
console.log( foo.getSomething() );//outputs 'something' in the console

Now all instances of Foo also have a getSomething method and a something property.

So what exactly’s going on here?

Typically classical inheritance is done like this:

var Foo = function(){
    ...
};
Foo.prototype = new Base(); //<-- here be troubles
Foo.prototype.constructor = Foo;

Even though this is perfectly fine in most cases, there’s one little catch that can cause problems: to set up the inheritance a new instance of Base is created. Obviously this can have serious unwanted side effects. One solution is to create a intermediate proxy that only holds the prototype of the Base class, but has a different (empty) constructor and instantiate the proxy instead of the original Base class.
That’s exactly what demiurge.extend internally does. It also adds a static __super__ member that holds a reference to the original base class. This can be used to call the super constructor, as in the example above, but also for referencing the original version of an overridden method:

Foo.prototype.getSomething = function(){
    return 'FOO:' + Foo.__super__.prototype.getSomething.call( this );
};

It’s definitely not ideal, but it’s better than nothing.

Object decoration

This differs from classical inheritance in the sense that it’s a single object that inherits the members from a class. Since it’s a derivative of the decorator pattern, I called the function decorate.

Example

Again we create 2 classes:

var Foo = function(){
    this.bar = 'bar';
};
Foo.prototype.getBar = function(){
    return this.bar;
};
var Baz = function(){
    this.qux = 'qux';
};
Baz.prototype.getQux = function(){
    return this.qux
};

var baz = new Baz();
//baz doesn't have a getFoo() method yet
baz = demiurge.decorate( baz, Foo );
console.log( baz.getFoo() );//outputs 'foo' in the console

var baz2 = new Baz();
//baz2 doesn't have a getFoo() method, only baz has.

A warning

The decorate method could be expensive to call for two reasons:
– it creates a new instance of Baz (without using the constructor of Baz though).
– it “manually” copies the members of Foo to the new instance and then calls the constructor of Foo

In most cases this won’t be a problem, but I wouldn’t use it to create hundreds or thousands of objects and decorate them (which would be silly anyway).

Prototypal inheritance

the createObject method is an almost exact copy of Douglas Crockford’s Object.create.

It was refactored into 2 functions, because I could use a part (demiurge.createProxy) of it in the demiurge.decorate function, which is why it’s added into this lib BTW.

However if the ES5 Object.create version is found that method is used instead, since it’ll be faster.

Example

var baz = {
    qux : 'qux',
    getQux : function(){
        return this.qux;
    }
}

var o = demiurge.createObject( baz );
console.log( o.getQux() )//outputs 'qux' in the console

Feedback

As it goes with these things, it could be I’ve missed something important in the lib itself or in the examples. If I did, let me know in the comments or send me a tweet @camillereynders

Credits

None of the concepts are my invention, I just brought them together. A lot is based on these two posts by Douglas Crockford:

IMO both have some merits and can be used depending on what you want to do.

Advertisements
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: