Blueshell

A microlibrary for inheritance with prototypal inheritance tools allowing class-like construction.

Website:https://github.com/jgnewman/blueshell

Blueshell.js

A simple, clean, straightforward and powerful inheritance engine for all JS environments.

Version 2.0 contains:

  • No more BS joke :)
  • "Infinitely" chainable prototypes that are super easy to make
  • A simpler, smarter, stricter interface
  • Prototypes accessible in EVERY JS environment including IE

Blueshell.js is a powerful inheritance microlibrary for JavaScript. It's also an experiment into doing inheritance a little differently than you might have seen before.

Blueshell is uniquely suited to dealing with classical inheritance and prototypal inheritance alike. Prototypes created with BlueShell are even accessible in IE 8 (not tested in 7) and, of course, it passes JSLint.

Note: BlueShell syntax is not like Java syntax. You won't need any new anything.

Here's how it works:

Installation

BlueShell can be installed anywhere and binds a namespace called BlueShell or B to the global object by default. In the browser, just include the JS file. Anywhere else, just do what you'd normally do.

Usage

First and foremost, any objects you intend to touch directly or indirectly with BlueShell need to be created using BlueShell. If you ignore this rule, you won't get seamless, retrievable prototypes.

To create an object, use BlueShell.create. Remember that B can be used as a shortcut for "BlueShell".

var person = B.create({
    name: 'john',
    age: 28
});

Doing this engages the background work that makes retrieving prototypes possible. Your result is an instance of Inherit.ClassChain and looks something like this:

// Inherit.ClassChain =>
{
    name: 'john',
    age: 28,
    __proto__: Object {
        isClassChain: true,
        getProto: [FUNCTION],
        protoRef: '1342644884033-1000001-bbbXbQ2x9K56V7wcLBB29NBdm'
    }
}

Notice that B.create will give your object a universally unique prototypal protoRef property. This reference is necessary for BlueShell's advanced prototypal inheritance and is the reason you need to create all of your objects with B.create.

Classical Inheritance

If you want to create a new object that classically inherits properties from another object, you can use B.create for this as well. In this use case, you have the option of passing in up to three arguments.

var person = B.create({
    name: 'john',
    age: 28
});

var kid = B.create(person, B.create({
    age: 42,
    hair: 'brown'
}));

kid;
// Inherit.ClassChain =>
{
    name: 'john',
    age: 42,
    hair: 'brown',
    __proto__: Object {
        isClassChain: true,
        getProto: [FUNCTION],
        protoRef: '1342645295780-1000004-MYpaly2PKxpPPzM6sWN0hUJ96'
    }
}

When using .create in this way, your first argument constitutes the object to be used as a parent and the second argument constitutes an object full of mixins and overrides.

If it so happens that your parent object has been attached to a prototype via BlueShell, your new child object will be bound to the same prototype unless you explicitly tell BlueShell not to do this. You can state this explicitly by passing in the value false as a third argument to .create.

Prototypal Inheritance

Binding objects to prototypes with BlueShell is much easier than in native JavaScript. Let's say you have an object you want to use as a prototype:

var personActions = B.create({
    getName: function () { return this.name; },
    getAge: function () { return this.age; }
});

You can create a new object using personActions as its prototype with the method BlueShell.bindProto:

var person = B.bindProto(personActions, B.create({
    name: 'john',
    age: 28
}));

person.getName();
// => 'john'

person.getAge();
// => 28

person;
// Inherit.ClassChain =>
{
    name: 'john',
    age: 28,

    __proto__: Inherit.ChainLink {
        protoRef: '1342706794368-1000008-1WZVGxUT3dSxdrS6wlYgFOCcD',

        __proto__: Inherit.ClassChain {
            getName: function () { return this.name; },
            getAge: function () { return this.age; },

            __proto__: Object {
                getProto: [FUNCTION],
                protoRef: '1342645295780-1000004-MYpaly2PKxpPPzM6sWN0hUJ96'
            }
        }
    }
}

Once you have created an object with an attached prototype, you can actually use your new object as the prototype for another object. Feel free to nest your prototypes as deep as you like.

var child = B.bindProto(person, B.create({
    hair: 'brown';
}));

child;
// Inherit.ClassChain =>
{
    hair: 'brown',

    __proto__: Inherit.ChainLink {
        protoRef: '1342706790790-1000003-7NBHANoQGn5MNELQ4yb5pkWMb',

        __proto__: Inherit.ClassChain {
            name: 'john',
            age: 28,

            __proto__: Inherit.ChainLink {
                protoRef: '1342706794368-1000008-1WZVGxUT3dSxdrS6wlYgFOCcD',

                __proto__: Inherit.ClassChain {
                    getName: function () { return this.name; },
                    getAge: function () { return this.age; },

                    __proto__: Object {
                        getProto: [FUNCTION],
                        protoRef: '1342645295780-1000004-MYpaly2PKxpPPzM6sWN0hUJ96'
                    }
                }
            }
        }
    }
}

Then, of course, if you modify a prototype, the change propagates to the children:

personActions.getHair = function () { return this.hair; };

child;
// Inherit.ClassChain =>
{
    hair: 'brown',

    __proto__: Inherit.ChainLink {
        protoRef: '1342706790790-1000003-7NBHANoQGn5MNELQ4yb5pkWMb',

        __proto__: Inherit.ClassChain {
            name: 'john',
            age: 28,

            __proto__: Inherit.ChainLink {
                protoRef: '1342706794368-1000008-1WZVGxUT3dSxdrS6wlYgFOCcD',

                __proto__: Inherit.ClassChain {
                    getName: function () { return this.name; },
                    getAge: function () { return this.age; },
                    getHair: function () { return this.hair; },

                    __proto__: Object {
                        getProto: [FUNCTION],
                        protoRef: '1342645295780-1000004-MYpaly2PKxpPPzM6sWN0hUJ96'
                    }
                }
            }
        }
    }
}

child.getHair();
// => 'brown'

The instances of Inherit.ChainLink are part of what makes the prototypes cross-environment compatible. In practice, you can pretend they don't even exist. When you want to retrieve an object's prototype, just invoke someObject.getProto() and it will return the most immediate prototype attached to an object disregarding the chain links.

child.getProto();
// Inherit.ClassChain =>
{
    name: 'john',
    age: 28,

    __proto__: Inherit.ChainLink {
        protoRef: '1342706794368-1000008-1WZVGxUT3dSxdrS6wlYgFOCcD',

        __proto__: Inherit.ClassChain {
            getName: function () { return this.name; },
            getAge: function () { return this.age; },
            getHair: function () { return this.hair; },

            __proto__: Object {
                getProto: [FUNCTION],
                protoRef: '1342645295780-1000004-MYpaly2PKxpPPzM6sWN0hUJ96'
            }
        }
    }
}