Prior to getting into jQuery, I was a big fan of the YUI (still am) and found myself using a lot Yahoo/Crockford like coding patterns, specifically the module/singleton pattern.
When I started using jQuery, I’d try something like this to encapsulate the code that makes the ajax request (startAjax), processes the ajax request (catchAjax), and then proceeds with program flow (doStuffAfterAjax)
var FOO = function(){
return {
startAjax:function(the_url){
$.get(the_url,{},this.catchAjax);
},
catchAjax:function(data){
//do stuff with the data
//BAD CODE: this won't work
this.doStuffAfterAjax();
},
doStuffAfterAjax:function(){
}
}
}();
//...
//...
This would sort of work, but the this variable would lose its FOO context from the catchAjax function, because jQuery is using it as a callback.
The quick solution was to forgo the use of “this”, and always refer to the object by its global name, FOO.
var FOO = function(){
return {
startAjax:function(the_url){
$.get(the_url,{},FOO.catchAjax);
},
catchAjax:function(data){
//do stuff with the data
//Working code, but still kind of BAD
FOO.doStuffAfterAjax();
},
doStuffAfterAjax:function(){
}
}
}();
//...
//...
This would work, but is an ugly hard-coded hack that would prevent future objects from inheriting/reusing any of the code in your object.
After refreshing myself on the finer points of Javascript’s closures, I’m now using
var FOO = function(){
return {
startAjax:function(the_url){
var that=this;
$.get(the_url,{},function(data){
//"this" doesn't refer to FOO from here
//so we use "that" (assigned above)
that.catchAjax(data);
});
},
catchAjax:function(data){
//do stuff with the data
//Good CODE: yay!
this.doStuffAfterAjax();
},
doStuffAfterAjax:function(){
}
}
}();
//...
//...
Here we’re using an anonymous function as the callback, but using it to call our own AJAX handler. We get away with this by, outside of the callback function, assigning the value of this (which, at the time of assignment, is equal to FOO) to a new variable named that. The variable that is available in the anonymous function because closure says that inner functions have access to outer variables in the same scope (aka, the anonymous function is in the same scope as the variable that)
Framework Value
After 3+ years of official AJAX development, (longer if I go back to my DHTML days), I’m still hesitant to fully embrace any particular framework. I primarily look to the framework to handle the Big Ticket cross browser issues. Things like
- Making the actual AJAX request
- Hooking up Event Handlers
-
Simplifying DOM selection (hello jQuery!)
It’s probably the nature of my work (lots of contracting). One shop may be using YUI, another may be using jQuery. By not tying myself to a particular framework I keep myself flexible.
Design Patterns vs Built Ins
This also got me thinking about all OOP Javascript techniques out there.
There a certain risk/tradeoff you make when using design patterns to simulate concepts that are built in to other languages. Unless your team, and the team that replaces you (there’s always a team that replaces you) is familiar with the pattern you’re using, they’re going to be groping in the dark when debugging and/or reusing your code 6 months later.
Good documentation remains essential, as well as comments that will shed light on what you’re doing. Even if your design pattern seems as simple and natural as assigning a variable to you, unless it’s a core language concept let the world know what you’re doing.