Instead of explaining to you what closure is, I’m going to show you some examples of how closure is used and walk you through the process of designing your application to take advantage of closure.
Here we go!
What is a Closure?
A closure is a way to access and manipulate external variables from within a function.
I like to think of a closure as a feature of the programming language to let us do cool things such as:
Let’s try a couple of things based on the function we created in the recursion example:
So far so good…
…Uh oh what happened?
- incrementUntil also maintains a closured reference to num and can read and modify it. The scope of num is window if you typed this example as-is directly into the browser console.
- Although incrementUntil is being executed inside of myFun2, it didn’t modify the num in myFun2’s scope because incrementUntil only recognizes the num that was inside of its parent’s scope when it was first created (e.g., window). It doesn’t recognize the num inside of the caller, myFun2, because it doesn’t maintain a closured reference to its caller’s scope.
Here’s how we can fix myFun2 so it can leverage the incrementUntil function to modify the num inside of its own scope.
The “fix” for myFun2 seems to work fine but it lends itself to a lot of duplicate code. What if we have to increment variables inside of other functions? It’s not good practice to copy-paste the same function/code into multiple places. Let’s refactor our incrementUntil function using partial application:
The refactored incrementUntil function does not read or modify anything outside of its own scope so it’s a pure function, which illustrates a core principle of functional programming. You call the function as follows: incrementUntil(max)(num), which reads “increment until max starting from num”.
A really nice thing about partial application is that we can partially evaluate the final solution by providing our function a subset of the arguments it needs. Then we can save the intermediate solution to a variable so we can save ourselves some processing time by eliminating the need to evaluate the same intermediate solution every time we call the function to do similar things (assuming your programming language supports this kind of optimization).
Here’s what I mean by that in code:
What’s happening in the code above is that you created a closure to keep the value passed to the function multThenAdd even after the inner function is returned. The inner function that is being returned is created within an outer function, making it a closure.
The above code is equivalent to the following in ES6:
var multThenAdd = num => mul => add => num * mul + add
Quite elegant but the syntax could seem really strange for someone coming from an imperative language background.
Now you’ve seen partial application in action, here’s a high level discussion on the concept of partial application (also called currying by some).
Partial application is basically a design pattern where your function returns another function that takes an argument. For example, you can call your function like this: myFun(arg1)(arg2), which is equivalent to:
const myFun2 = myFun(arg1)
Partial application is a powerful design pattern because you can continuing chaining things like myFun(arg1)(arg2)(arg3)… What’s happening here is akin to an assembly line in a factory: One argument at a time is applied to myFun to evaluate a better and better partial solution until all the arguments are applied to provide a complete solution.
Here’s an actual piece of code I wrote for a Node/Express app that uses the partial application pattern:
Thanks for reading! Here are some resources that that inspired me to create the content of this article:
- Everything You Need to Know about Scopes
- Making Functional Programming Click
- MDN Closure Tutorial
- Tricky Interview Question On Closure and Scope