Monday, February 24, 2014

SnowBlower and Object Composition

~function(window, define, module, Array, Object){
'use strict';
var slice = Array.slice, create = Object.create;
function partial(func) {
var args1 = slice.call(arguments, 1);
return function(){
return func.apply(this, args1.concat(slice.call(arguments)));
};
}
function mixIn(target, ref) {
for (var key in ref) {
if (ref.hasOwnProperty(key)) {
target[key] = ref[key];
}
}
return target;
}
function argsMixInExec(args, prev, next) {
typeof next === 'function' ? next.apply(prev, args) : mixIn(prev, next);
return prev;
}
function SnowBlower(proto) {
var closures;
proto = proto || {};
closures = slice.call(arguments,1);
return function() {
return closures.reduce(partial(argsMixInExec, slice.call(arguments)), create(proto));
};
}
SnowBlower.mixIn = mixIn;
SnowBlower.partial = partial;
if(define){
define(SnowBlower);
} else if(module) {
module.exports = SnowBlower;
} else {
window.SnowBlower = SnowBlower;
}
}(typeof window !== 'undefined'?window:{},typeof define==='function'?define:null,typeof module!=='undefined'?module:null,[], Object);
view raw SnowBlower.js hosted with ❤ by GitHub

I'm going to talk about this "library" and why it's very useful. It takes a lot of the compositional techniques of objects and makes it really fun.

Here's an example of how to use SnowBlower.

~function(window, SnowBlower){
var Proto = {
//prototype stuff here
};
function _defaultParameters(options) {
if(!options){
throw new Error("options is not defined");
}
options.x = options.x || 0;
options.y = options.y || 0;
options.width = options.width || 100;
options.height = options.height || 100;
}
function _sprite () {
//"this" is the sprite you are making
this.x = options.x;
this.y = options.y;
this.width = options.width;
this.height = options.height;
}
var SpriteFactory = SnowBlower(Proto, _defaultParameters, _sprite);
window.SpriteFactory = SpriteFactory;
}(window, SnowBlower);
view raw Sprite.js hosted with ❤ by GitHub

It takes all the functions and objects that you pass to it, and either executes it in the context of your new object, or mixes it into your new object. If you need polyfills for your environment, just define Array.prototype.reduce, Object.create, and replace the Object.prototype.hasOwnProperty function to reflect your environment.

It's designed to be small and SnowBlower assumes you have all the pieces and closures that define your object up front. If you need to compose factories, you can just create a function that does it for you.

var proto = {};
function PartialFactory() {
var args1 = [proto].concat([].slice.call(arguments));
return function(){
return SnowBlower.apply(this, args1.concat([].slice.call(arguments)));
};
}
//Now pass some arguments to PartialFactory to predefine your factory

This is a DRY method of reusing functions you have already defined to compose objects. The sky is the limit! Just thought I would share this compositional technique with you.

~function(){console.log('josh')}();

No comments:

Post a Comment