I have been asked many times what closures are and how they work. There are many resources available to learn this concept, but they are not always clear to everyone. This has led me to put together my own approach to exchanging the information.
I will supply code samples.
//> denotes an output or return.
Introduction to functions
If a function does not have a return statement, it will implicitly return undefined, which brings us to the simplest functions.
Noop typically stands for no operation; it takes any parameters, does nothing with them, and returns undefined.
The identity function takes in a value and returns it.
1 2 3 4 5 6
The important thing to note here is that the variable (value) passed in is bound to that function’s scope. This means that it is available to everything inside the function and is unavailable outside of it. There is an exception to this, being that objects are passed by reference which will prove useful with the use of closures and currying.
Functions that evaluate to functions
1 2 3 4 5 6 7
This is a function that returns a function which returns true.
Functions take arguments and those arguments can be values or reference types, such as functions. If you return a function, it is that function you are returning, not a new one (even though it might have just been made to return).
Creating a closure is nothing more than accessing a variable outside of a function’s scope (using a variable that is neither bound on invocation or defined in the function body).
Let’s review the identity function:
The value, a, is bound inside of the function and is unavailable outside of it; there is no closure here. For a closure to be present, there would need to be a function within this function that would access the variable a.
Why is this important?
- Closures provide a way to associate data with a method that operates on that data.
- They enable private variables in a global world.
- Many patterns, including the fairly popular module pattern, rely on closures to work correctly.
Due to these strengths, and many more, closures are used everywhere. Many popular libraries utilize them internally.
Let’s take a look at an example of closure in action:
1 2 3 4 5 6 7 8 9
The outer function (foo) takes a variable (x), which, which is bound to that function when invoked. When the internal function (bar) is invoked, x (2) and y (2) are added together then logged to the console as 4. Bar is able to access foo’s x-variable because bar is created within foo’s scope.
The takeaway here is that bar can access foo’s variables because it was created within foo’s scope. A function can access variables in its scope and up the chain to the global scope. It cannot access other function’s scopes that are declared within it or parallel to it.
No, a function inside of a function doesn’t have to reference variables outside of its scope. Recall the example function which returned a function which evaluated to true:
1 2 3 4 5 6 7 8
No matter what is passed to foo, a function that evaluates to true is returned. A closure only exists when a function accesses a variable(s) outside of its immediate scope.
This leads into an important implication about closures, they enable you to define a dataset once. We’re talking about private variables here.
Without closures, you recreate the data per function call if you want to keep it private.
1 2 3 4 5 6 7
We can do better! With a closure, we can save it to a variable that is private, but only instantiated once.
1 2 3 4 5 6 7 8 9 10
Currying is the process of transforming a function with many arguments into the same function with less arguments.
That sounds cool, but why would I care about that?
- Currying can help you make higher order factories.
- Currying can help you avoid continuously passing the same variables.
- Currying can memorize various things including state.
1 2 3 4 5 6 7 8
By currying the msg function so the first variable is cached as “Hello,”, we can call a simpler function, hello, that only requires one variable to be passed. Doesn’t this sound similar to what a closure might be used for?
In the discussion of functional programming concepts, there is often a sense of resistance.
The thing is, you’ve probably already been functionally programming all along. If you use jQuery, you certainly already do.
1 2 3 4
Another place you may have seen this is utilizing the map function for arrays.
1 2 3 4 5 6
We’ve seen some examples of closures and how they can be useful. We’ve seen what currying is and more importantly that you’ve likely already been functionally programming even if you didn’t realize it. There is a lot more to learn with closures and currying as well as functional programming.
I ask you to:
- Work with closures and get the hang of them.
- Give currying a shot.
- Embrace functional programming as an additional tool that you can utilize to enhance your programs and development workflow.
Additional readings and inspirations
- MDN Closures
Check out how you can utilize closure and currying to manage state throughout a stateful function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Checkout how closures and currying can be used to create higher order functions to create methods on the fly: http://jsfiddle.net/GneatGeek/A9WRb/