Closures translated from traditional JS to ES6 made easy

Written by Hunter Jansen on April 25, 2017

A topic that’s come up a few times over the past couple of months has been closures and a general confusion about how they’re used, how to explain them and how ES6 changes them (hint: it doesn’t?). So I put together a few examples of common closures that people have probably seen or used in the wild without knowing the name for it.

I then take these examples and update them to a more modern syntax taking advantage of ES6. Most of the base examples are derived from the excellent resources at mozilla, that I changed to match the sort of stuff I wanted to show a little bit better.

But wait; what is a closure?

A closure at it’s absolute simplest is a function that accesses variables from its creators scope. Closures remember this scope, even after enclosing scope’s life has ended.

If I return function a that was created inside function b - function a will remember function b’s existence.

It’s a little weird to think about from explanations, so let’s look at an example.

Example 1 - Animorphing a simple example

The code above is a classic example of a closure, and is the typical one used when explaining the basics. Let’s break it down into bullets:

  • The makeFunc receives a variable called -name- and keeps it as a local variable
  • The -displayName- function is an inner function that can only be called inside of the -makeFunc- function.
    • Note that the -displayName- function has no inner variables defined in it’s own scope
  • Because inner functions have access to variables of their outer function, -displayName- has access to the name variable inside of -makeFunc-

So on line 7 when we call var myFunc = makeFunc('Hunter'); - myFunc essentially ends up with the value of:

  var name = 'Hunter'; // From outer function scope
  function displayName() {
    console.log('Hello ' + name);
  }

So as we call myFunc() it executes the displayName function and console logs: Hello Hunter - neat!

Let’s collapse it

This is the same as above, except this time instead of saving the inner function to a variable inside of the makeFuncCompressed function, we immediately return it. It’s a more terse way to complete what we did in the first example, but it’s pretty much entirely the same - nothing too ground breaking here, but it’s a baby step to get us to our final point.

Let’s convert it

This third example starts converting from traditional JS to a more ES6 syntax. We keep the same visual code structure as the previous example, but we use some newer syntax including arrow functions, and string interpolation. Aside from the minor tweaks, we’re basically looking at the same code.

Making it ES6exy

After taking advantage of ES6 a little bit more, this is where we end up - a simple one liner that equates to the same closure code as in the very first example. Let’s take a look at what’s changed:

  • function calls with a single argument don’t need brackets around them - so (name) => {something} can just be name => {something}
  • If your call is all in the same line, you can negate the curly braces - so name => {something} becomes name => something
  • In ES6 with a concise body, only an expression is needed, and an implicit return is attached
    • So instead of name => return ()=> something we can remove the return and end up with name => () => something
  • finally we get down to the actions inside of the closure itself with the console.log

The code above doesn’t LOOK like a closure as many people identify them, so hopefully breaking it out into a more traditional sort of code structure helps get over that initial hurdle.

Example 2 - Multiple arguments

The last example had a closure with a function that only accessed its outer function’s variable, but didn’t have any variables inside of it’s own scope. What if we want to have a closure that receives its own variable when you call it? It’s practically the same thing.

This example is very similar to the last one - except the closure recieves a variable as well:

  • the outer function gets variable x
  • the closure gets variable y, but also has access to x
  • calling var base5 = makeAdder(5) sets x as 5 so that when we call . . .
  • base5(15) the closure is running var x = 5, y = 15; return x + y; giving us 15 as a return value from this closure call

Update the example

If we follow the same steps as last time - keep the same structure, but update the syntax we end up with:

This is the exact same thing, we just dropped the function keywords and used arrow functions instead; once again, no major changes - but it gives us a stepping stone to our final destination.

Bringing es6exy back

As you can see, this looks a lot like the es6 version of the first example - here’s a couple things to note:

  • the braces and curly braces are both removed again
  • we call the outer function with a parameter the same as in example one and it gets assigned to x
  • this time instead of no arguments, the inner function recieves a param that goes to y
  • because we’re returning the sum of the two variables and not doing anything else - we can just leave it as x + y
    • As mentioned before, a return is implicitly attached to this statement, letting us create and call the function as above

We’ve covered a lot - take a breather, because we’re juuust over half done! Deep Breath

Ok, let’s go.

Example 3 - slightly more realer worlder

Traditionally I personally have found myself using closures more inside of an objecty way as in this below example - using an object as an alternative to a class an inner object with a series of functions that interact with ‘private’ variables in the original object. This is used in a common pattern of JS dev called the module pattern. You see this pattern all over the place in apps that don’t use any framework, but you do also find it used in of frameworks as well; most notably in my experience, Angularjs.

This is basically the closure counter example from mozilla with an extra closure tossed in; let’s take a look at what’s happening:

  • counter is assigned to an IIFE
    • this makes the privateCounter variable and changeBy scoped to the inside of the IIFE - acting as private variables only accessible from inside the scope of the IIFE
  • the IIFE returns an object with several functions
    • so counter becomes an object with multiple functions
    • all of these functions have access to the private variables/functions definted in the IIFE’s scope - in fact, they’re all closures!
  • the functions themselves are pretty normal - except for the addMultiplier which is a closure function that acts very similar to our second example
  • to access the closures that are inside of the counter object we call them the same way we would any other object assigned to a variable
    • counter.increment();
  • this goes the same for our closure addMultiplier
    • var multiAdd = counter.addMultiplier(2);
    • multiAdd(3);
    • which you could think of as calling changeBy((2 * privateCounter - privateCounter) * 1);

I’m running out of ES6 puns

Though the es6 version is much more terse, it does the same thing as the above example and behaves exactly the same. All of the principles from the first two examples are at play in this example - and the first thing you notice is that the amount of code is drastically reduced. The lines of code are cut in half! You could also make the argument that the code is a lot cleaner and and easier to read; now we’re seeing the power of closures cleaned up and made more easily readable thanks to ES6

A closure gotcha - cured with ES6

One of the most common gotchas that trip people up, like all the time, because you don’t expect it sometimes, is using closures inside of a loop. Since the inner functions have access to the outer function’s scope, some unexpected things can happen.

Wait. Wat?

Gotcha

  • We do a loop of 1 - 5 and have a closure inside of the loop that appends the index to an array. So we EXPECT to have an array of [1,2,3,4,5].
  • Nope - because of the async nature of timeout calling the internal function after 100ms, the loop itself has already completed its cycle and incremented the index to 6.
  • Since all of the closures are executed AFTER the loop’s finished AND they’re all accessing the same parent variable i (which is now 6, because the loop is done) - each closure pushes the number 6 to the array
  • lol

Ok, how do I fix it?

There’s actually a couple of ways you can get around this, but the one I like the most for traditional JS is to wrap the internal function with an IIFE that you pass the index into.

By using an IIFE to wrap the functionality each iteration of the loop now has its own scope and everything behaves as expected.

But wait; there’s more!

Once again, es6 swoops in to make your life easier. By using let instead of var to assign i, each closure assigns the scoped variable inside of the loop and everything works as expect. I think of it as freezing the variable inside of the scope of the loop and blocking it from being touched outside of that iteration of the loop.

Wow.

It's done

That’s it. It’s over!

Setting out to write this post, I was hoping to create a resource to demonstrate some examples of closures and how they look traditionally and in ES6 in a way that’s easy to follow and totally non-cryptic. Hopefully I’ve done that; hopefully you’ve learned something(?); and hopefully if anything, you’ve become additionally inspired to investigate closures!

Got any feedback, questions, or suggestions to improve this post?

Hit me up on twitter (link in the footer), or drop me a line at hunter@hyperwidget.com - I’d love to hear from you!

Happy Hacking and keep it #es6exy! -Hunter