So you have been asked to create some sort of callback history, or maybe trace how you have got to a certain point and be able to “roll back” previous states of your application. I have recently discovered a very interesting use for closure callbacks that enables just the thing. Most people would freak out, but really this is just a design pattern based on linked objects in traditional languages (only more easy!).
So lets get on with the example.
var PresidentTracer = new (function(){
var presidenttracer = this;
var presidentCurrent;
var presidentCallback;
var presidentCallforward;
presidenttracer.addPresident = function(presidentName){
var current = presidentCurrent;
var callback = presidentCallback;
presidentCurrent = presidentName;
//callback history
presidentCallback = function(){
presidentCurrent = current;
presidentCallback = callback;
};
};
presidenttracer.nextPresident = function(){
var current = presidentCurrent;
var callback = presidentCallback;
var callforward = presidentCallforward;
if(presidentCallforward!=null){
presidentCallforward();
presidentCallback = function(){
presidentCurrent = current;
presidentCallback = callback;
presidentCallforward = callforward;
}
}
};
presidenttracer.previousPresident = function(){
var current = presidentCurrent;
var callback = presidentCallback;
var callforward = presidentCallforward;
if(presidentCallback!=null){
presidentCallback();
presidentCallforward = function(){
presidentCurrent = current;
presidentCallback = callback;
presidentCallforward = callforward;
}
}
};
presidenttracer.currentPresident = function(){
return presidentCurrent;
};
})();
This is basically linked lists through closures… It can get even more interesting then this though, we could if we wanted to pass in a closure to get executed on each president switch as follows.
var PresidentTracer = new (function(){
var presidenttracer = this;
var presidentCurrent;
var presidentCallback;
var presidentCallforward;
var switchCall;
presidenttracer.addPresident = function(presidentName, callOnSwitch){
var current = presidentCurrent;
var callback = presidentCallback;
var switcher = switchCall;
presidentCurrent = presidentName;
switchCall = callOnSwitch;
callOnSwitch();
//callback history
presidentCallback = function(){
switchCall = switcher;
presidentCurrent = current;
presidentCallback = callback;
};
};
presidenttracer.nextPresident = function(){
var current = presidentCurrent;
var callback = presidentCallback;
var callforward = presidentCallforward;
var switcher = switchCall;
if(presidentCallforward!=null){
presidentCallforward();
switchCall();
presidentCallback = function(){
presidentCurrent = current;
presidentCallback = callback;
presidentCallforward = callforward;
switchCall = switcher;
};
}
};
presidenttracer.previousPresident = function(){
var current = presidentCurrent;
var callback = presidentCallback;
var callforward = presidentCallforward;
var switcher = switchCall;
if(presidentCallback!=null){
presidentCallback();
switchCall();
presidentCallforward = function(){
presidentCurrent = current;
presidentCallback = callback;
presidentCallforward = callforward;
switchCall = switcher;
};
}
};
presidenttracer.currentPresident = function(){
return presidentCurrent;
};
})();
so lets test it out!!!
PresidentTracer.addPresident('fruit',function(){alert('zoop');})
PresidentTracer.addPresident('whoAmI',function(){
alert(PresidentTracer.currentPresident());
});
PresidentTracer.addPresident('neto',function(){alert('dynamic callbacks');})
PresidentTracer.currentPresident();
PresidentTracer.previousPresident();
PresidentTracer.nextPresident();
PresidentTracer.nextPresident();
PresidentTracer.previousPresident();
PresidentTracer.previousPresident();
It works! Long story short, this example shows off the dynamic nature of javascript as well as closures and callbacks. Many people have yet to understand the power of such language features, but if used correctly they can simplify programming, and give you syntactical expressiveness.
The author,
Matt Prokes
Posted in Design Pattern, Javascript |