Closures are one of the most powerful features of the JavaScript language, and also one of the least understood. Simply put, a closure is an object that retains access to the lexical scope in which it was created. Remember that in JavaScript, functions are first class objects, they can be assigned to variables, passed as arguments etc.
Take the following example:
function myFunction() {
var i = 0;
return function () {
alert(++i);
};
};
var myFunction2 = myFunction(); //myFunction is now out of scope
myFunction2(); //displays 1
myFunction2(); //displays 2
myFunction2(); //displays 3
What happened? The function returned by myFunction retains access to the local variable i - this is a closure. JavaScript maintains not just the returned function, but a reference to the environment in which it was created - including all the local variables in scope at that time.
So, why is this useful? Well, one excellent use is encapsulation, allowing an object to expose a public API whilst keeping it’s internal data and functionality private.
Consider this example:
function myObject() {
var i = 0;
function increment() {
return ++i;
};
function decrement() {
return —i;
};
return {
PlusOne: function () {
alert(increment());
},
MinusOne: function () {
alert(decrement());
}
};
};
var myObjectInstance = myObject();
myObjectInstance.i = 1; //fails, private variable
myObjectInstance.increment(); //fails, private function
myObjectInstance.PlusOne(); //displays 1
myObjectInstance.PlusOne(); //displays 2
myObjectInstance.MinusOne(); //displays 1
Our MyObject function has a locally-scoped variable “i”, and two locally-scoped functions, “increment” and “decrement”. The return value is an object (defined with object literal notation) that defines two functions, “PlusOne” and “MinusOne”. These functions are public, but they access the private functions “increment” and “decrement” via the closure provided by myObject’s context. This is starting to look a little like private methods and variables in classical OO…
Taking it one step further, we can introduce a variation on the classic GoF singleton pattern by making the function execute and return immediately with the following syntax:
var myObject = (function () {
var i = 0;
function increment() {
return ++i;
};
function decrement() {
return —i;
};
return {
PlusOne: function () {
alert(increment());
},
MinusOne: function () {
alert(decrement());
}
};
})();
Our object is now instantiated and ready to use:
myObject.PlusOne();
myObject.PlusOne();
This is generally referred to as the JavaScript Module Pattern, and attributed to Douglas Crockford. For a concise synopsis: http://www.yuiblog.com/blog/2007/06/12/module-pattern/. It’s a very useful pattern, lending itself to modularization of JavaScript code.
There are pitfalls, some of which I’ll go into in future posts. However, carefully used closures lend themselves to clean, powerful, maintainable JavaScript code.
No comments:
Post a Comment