Introduction
This is a very simple tip to show how can we increase the power of Object Oriented JavaScript with the help of closure. I assume that everyone who reads the tip has a basic idea about Closure.
Using the Code
As I mentioned, this is simple tip so I will try to make my examples very simple and understandable.
To call a JavaScript function, we can use function.apply(context,arguments)
.
Consider the below example. Here, I am trying to hold the reference of the Add
and Subtract
functions to my Calculator
objects to add and sub properties respectively so that on $(function(){})
(document ready), I can access those two by calling Calculator.add()
or Calculator.sub()
. Look at the code below and think, will it satisfy our goal or not? The answer is: No. Rather, holding the function it will execute itself first on document ready give alert of 30 and 10 . Surprise!!!!! No problem, I will explain to you.
<script type="text/javascript">
function bind(context, fn, args) {
return fn.apply(context, args || []);
}
function Add(a, b) {
alert(a + b);
}
function Subtract(a, b) {
alert(a - b);
}
$(function () {
var Calculator = {
add: bind(this, Add, [10, 20]),
sub: bind(this, Subtract, [20, 10])
};
});
</script>
This code actually generates the following output at run time:
var Calculator = {add : Add(10,20), sub: Subtract(20,10)};
It gives a clear indication that while Calculator
object initializes itself on document ready, it's actually assigning the output of Add
and Subtract
method to Calculator.add
and Calculator.sub
properties respectively, rather than wrapping the functions to it. That is why we are facing the alert .
So now, how can we hold the function to our Calculator
object? Look at the below example - it will satisfy our requirement. Run the below code and feel the difference:
<script type="text/javascript">
function bind(context, fn, args) {
return function () {
fn.apply(context, args || []);
}
}
function Add(a, b) {
alert(a + b);
}
function Subtract(a, b) {
alert(a - b);
}
$(function () {
var Calculator = {
add: bind(this, Add, [10, 20]),
sub: bind(this, Subtract, [20, 10])
};
});
</script>
Points of Interest
Did you notice the trick? Yes, the below code makes the difference. The magic of Closure, it gives you function scoping.
return function () {
fn.apply(this, args || []);
}
Actually the Calculator
object here plays a different role while it is initialing at run time, it generates the below code:
var Calculator = {
add: function () { bind(this, Add, [10, 20])},
sub: function () { bind(this, Subtract, [20, 10])}
};
It wraps the function to its property rather than assigning its value.
Now you can call your functions through your Calculator
object like this:
Calculator.add();
Calculator["sub"]();