Nov
10
2009
Linked Lists In Closures
Author: mprokesSo 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();

