NetBen Ramblings about JavaScript and frontend development.

11Mar/10Off

Presenting objection.js

Quote from 'Design Patterns' from the gang of four.

Favor object composition over class inheritance.

With JSoo I wanted to provide tools for OO JS, but I was still thinking in terms of pseudo classical inheritance. Foolishly I created JSoo to be a prototype constructor and registry and loader. Well the register and loading part of JSoo made it's way to mikado which is still under development and the OO part went into Objection. I had to write Objection since I wanted a cleaner and clearer way of dealing with objects in preparation of ES5.

Presenting objection.js.

Objection is a tiny OO toolbox (just under 2kb minified) that can change the way your write your JS programs and you should at least give it a try if only to prepare yourself for ES5 goodness.

First of all, it offers #create though a teensy bit different from the ES5 (Object.create) implementation. If there's a initialise (or initialize) method on the to-be-cloned object, it will be invoked (without arguments) once the object is created offering an alternative to the pseudo classical constructor. Initialise should only be used to add new property instances to the new object where you don't want property references from the old object (ie. array/object properties). Most arguments passed to constructors are usually property setters, so augment the object through #create rather then using constructor arguments.

Example:

var Mammal = {
   initialise: function(){
      this.sounds.roar = 'some mammals can roar';
      this.roar();
   },
   roar: function(){
      alert(this.sounds.roar);
   }
};
 
var cat = Obj.create(Mammal , {
   sounds: {
      roar: 'miauws'
   }
}); // alerts 'miauws'
cat.roar(); // alerts 'miauws'
 
// intentfully omitting propertiesObject to illustrate that mammal.initialise gets invoked.
var dog= Obj.create(Mammal );
dog.roar(); // alerts 'some mammals can roar'

Why is this better then pseudo classical inheritance and constructors? First of all, we just describe the Mammal object as an object, not as a function and attaching properties to it's prototype. Instead of 'new' we call Objection.create() (Obj is an alias) at which point we can decide to leave the new instance as is or augment it with extra properties through a property descriptor (2nd argument) or we can mixin properties from another object alltogether. So we use reusable packets of properties rather then constructor arguments.

I just added the initialise/initialize method behaviour to mitigate one major ambiguous feature. All inherited/cloned properties are references by default, meaning that an object or array property on the parent object will be exactly the same as on the child object. This feature also manifests itself in the pseudo classical way of creating objects. I might dedicate a post on this in the future.

Another nice method in Objection, is the adapter method, which creates an adapter object to remap method names or add method combiners without changing the original object.

var incompat = {
   halloWereld: function(){
      alert('hello world!');
   },
   dagWereld: function(){
      alert('goodbye world');
   }
};
 
var compat = Obj.adapter(incompat, {
   'hello' : 'halloWereld',
   'bye' : 'dagWereld',
   'helloAndBye' : function(){
      this.halloWereld();
      this.dagWereld();
   }
});
 
compat.hello(); // alerts 'hello world!'
compat.bye(); // alerts 'goodbye world'
compat.helloAndBye(); // alerts 'hello world!' and 'goodbye world'

Possible uses for the adapter method, is to make all thos Selector engines that all choose different method names (grrr) plugable into all your programs. Simply remap 'select', 'find', 'query' to 'qsa' or whatever you find logical for a selector method ;)

Obviously, we also want to check if an object inherits from another object and though we can use 'isPrototypeOf' to do this. I've always found inheritance an obscure name, I mean, a ferarri IS a car, a cat IS a mammal...

var Mammal = {};
var Insect = {};
var Fish = {};
var Cat = Obj.create(Mammal);
var Dog = Obj.create(Mammal);
var Felix = Obj.create(Cat);
 
// #is
Obj.is(Felix, Cat); // true
Obj.is(Felix, Dog); // false
// #isAll
Obj.isAll(Felix, Cat, Mammal); // true
Obj.isAll(Felix, Insect, Cat); // false
// #isSome
Obj.isSome(Felix, Insect, Cat); // true
Obj.isSome(Felix, Dog, Insect); // false

Clear as rain isn't it?

And now finally, the #factory method, I'll just post the example right away.

var BasePizza = {
   orders: function(nr){
      this.total = this.total + (nr * this.price);
      this.ordered = this.ordered + nr;
   },
   ordered: 0,
   total: 0
};
 
var pizzaFactory = Obj.factory(BasePizza);
 
pizzaFactory.addType('hawai', {
   pineapple: true,
   ham: true,
   price: 12
});
 
pizzaFactory.addType('peperoni', {
   peperoni: true,
   price: 10
});
 
pizzaFactory.addType('delux', {
   olives: true,
   broccoli: true,
   anjovis: true,
   extraCheese: true,
   price: 14
});
 
var bart = pizzaFactory.create('hawai');
bart.orders(1);
 
var lisa = pizzaFactory.create('delux');
lisa.orders(1);
 
var homer = pizzaFactory.create('peperoni');
homer.orders(3);
 
var total = bart.total + lisa.total + homer.total; // 64

I could go on and on about possibilities and how this way of programming makes much more sense, instead, I'll just offer up some links and safe more indepth info for future articles.

Further documentation can be found here:
http://wiki.github.com/bgerrissen/objection/

Downloads:
http://github.com/bgerrissen/objection/downloads

Enjoy ;)

Filed under: JavaScript Comments Off
Comments (0) Trackbacks (0)

Sorry, the comment form is closed at this time.

Trackbacks are disabled.