In continuation with my previous article on creating a chainable JavaScript toolbox, I would like to show how we can leverage JavaScript callbacks for enhanced functionality.
As said previously, this is how libraries are designed and the concept is nothing new. This is just an attempt to explain certain core features of JS libraries.
The core idea of chaining is to return 'this', which is an instance of the class, in each method of the class. In this way, each method passes an object to the next method and hence the chain continues endlessly.
However, not every method can return 'this' always. e.g., consider a method like 'getValue', which is expected to return a value. It obviously can't return 'this' and so the chain is broken. In such scenarios, callbacks come to our rescue.
Consider the below code, which is an extension of the code in my previous article (The private variable 'value' and two functions 'getValue' and 'setValue' are added):
(function(){
var value='Hello world';
var mySpace=function(){
return new PrivateSpace();
}
var PrivateSpace=function(){
};
PrivateSpace.prototype={
init:function(){
console.log('init this:', this);
return this;
},
ajax:function(){
console.log('make ajax calls here');
return this;
},
cache:function(){
console.log('cache selectors here');
return this;
},
setValue: function(newValue){
value=newValue;
return this;
},
getValue: function(callbackFunc){
callbackFunc.call(this,value);
return this;
}
}
window.my$=mySpace();
})();
The 'getValue' function is expected to return a value. If it returns a value, it can't continue the chain as it did not return 'this'. To overcome the problem, we can use callbacks.
The first line of 'getValue' uses "Function.call()", which is a predefined JavaScript method. All it does is, it executes any given function in a desired context. The first param of "Function.call" overrides the 'this' variable of calling function(callbackFunc) and the second param serves as input param to the calling function(callbackFunc).
So, to access our 'getValue()' function, we should say:
my$.getValue(function(value){
console.log('value is: ',value)
});
Doesn't it look like jQuery event handling/ajax functions syntax? Yes, jQuery makes heavy usage of callbacks for attaining chainability.
The getValue() function accepts a function as an input parameter, which is being executed using "Function.call()" internally. This function can be either anonymous or a named function(i.e., you can pass a function handler as input to "getValue").
Since we are returning 'this' in the definition of 'getValue', we can even chain it with other functions like:
my$.getValue(function(value){
console.log('value is: ',value)
}).setValue('new value').init().ajax();
In the above code, we are achieving both chainability as well as returning data from our methods using callbacks. This solves the problem of breakage of JavaScript chains and hence it is very powerful.
This is something which really helped me in writing some critical utility functions in my project and thought it is worth sharing. Please let me know your suggestions.
Happy coding :)