Fri, Oct 14, 2011
What are closures?Wikipedia probably has a deeper and more accurate explanation for what a closure is, but in words that I would be able to understand:
Closures are functions that you define "on the fly" that have access to the same variables (the same scope) as they get defined in. You can store them as variables, pass them around between other functions, and generally get treated like a normal variable.
They make for some really interesting code.
Consider this example:
[gist id="1286313" file="example1.js"]
In this function, the logic to check if the string matches or not and the functionality of adding the string to the returned variable is defined in two places. If we were to make that more complicated or make changes, we'd have to make sure we make those changes in both places.
If we were to rewrite this example using a local closure, it would look like this:
[gist id="1286313" file="example2.js"]
The functionality becomes much cleaner. It's easy to add to or modify the logic to check the string, etc.
(note that that function was only written to illustrate my point, it's probably easy to make a better version of it that doesn't use closures, etc.)
passing in a closure to a functionHere's another example of how closures can be useful. Technically those are not really closures, but plain functions as variables, since they're not taking advantage of the scope in which they are defined - but it's a similar topic.
In this example we'll create a function that loops through an array of strings and executes a specific callback to determine if the element should be returned.
[gist id="1286313" file="example5.js"]
We're calling the function twice with the same array, but the first call will return the fruit that start with the letter "a" (apple and avocado) but the second one will return all the fruit whose name is more than 5 letters in length.
Again, a simple example but illustrative of the powerful stuff that can be achieved using closures.
Returning closures as variablesClosure become even more interesting when you think of a function that actually returns a closure. Here's an example:
[gist id="1286313" file="example3.js"]
This function does nothing but return another function. However that function gets called within the scope of the function that created it, which allows us to pass in a variable, which that function has access to.
That means that if you look at the last two statements, they are comparing the "other string" and "some string" to the string previously used when calling the function that created the closure.
That allows us to compare the string easily without passing in the first string again and again. This example is a bit of a brain-bender, but it's probably worth it to dwell on the concept for a few seconds.
The example doesn't have much use, but it is the most clean example I could think of to illustrate the point.
Here's another example that might be a bit more useful or have more real-world application:
[gist id="1286313" file="example4.js"]
There are probably a lot of jQuery users out there, so this might make more sense as a real-world example.
Now the function-producing function accepts a selector as an argument. That means we can pass in any jQuery selector and it will return a function that tells us if a particular jQuery object matches the selector.
Again, it's probably too much of an over-kill for such a simple example, but it's easy to imagine extending this to accept an array of selectors or some other type of condition, eg. traversing through the parents to find something out about them, and then being able to call that with a given array of selectors.
ConclusionThinking about code in closures is a very different beast than typical object oriented programming. They are in fact the pillar of functional programming and provide very unique brain-twisting ways to code.
They can easily be misused and there are certainly all kinds of ways where they just make things more complicated. Your scope can soon get out of control and it gets hard to read other people's code, but if used right they make allow us to simply have less code. Which is probably what we generally strive for.
Let me know if you have anything more to add or additional examples that you think could be useful.