JavaScript Arrow Functions and Closures
--
ES6 introduced a new syntax for functions, the so-called Arrow Functions. They are more concise and usually a better way of describing functions. Let’s see how they work:
By default the arrow function is anonymous, so you need to assign it to a variable if you want to call it later. The same could be done using the function
keyword.
Cool! But why should I use it? For starters, it looks better, doesn’t it? Take a look at how my code looks before and after using arrow functions.
Looks a lot better now! Take a good look and you’ll notice that I no longer need to use the return
keyword. If you omit the brackets, the value is automatically returned! This is particularly useful when you use inline functions, or when passing callbacks.
If you omit the brackets, the value is automatically returned!
What about Closures?
OK, so you agree that the code looks cleaner. But that’s not enough to convince you to start using the arrow function syntax. Well, there’s a hidden benefit to this: it solves some closure problems!
A closure is the combination of a function and the lexical environment within which that function was declared.
Let’s create a talking dog that barks his own name! Oh the wonders of coding…
Ok, so now if we run the code above we get a nice response:
rex.bark() // 'Woof, my name is Rex'
But in the process of training your now world famous talking dog you want to teach him the sitAndBark
method, where he is only allowed to bark after one second. And… it doesn’t work.
rex.sitAndBark() // 'Woof, my name is '
What happened? Here we have closures doing their work. The setTimeout
argument function defines this
inside its own scope, meaning you are trying to access this.name
inside this new function now. Since it does not have a name
property, the value resolves to undefined
.
How do we solve it? Well, we could use the bind
method to bind this
to the argument function.
Now this.name
works as we intended.
rex.sitAndBark() // 'Woof, my name is Rex'
Let’s introduce the arrow function syntax now!
And it works!
rex.sitAndBark() // 'Woof, my name is Rex'
What happened here? This works because arrow functions don’t have a separate this
. When trying to access this
inside an arrow function, since they don’t have their own this
defined, it’ll fall back to the previous scope, which is the class scope in this case. A much better approach than having to bind all your functions!
Arrow functions don’t have a separate
this
. When trying to accessthis
inside an arrow function it’ll fall back to the previous scope, since they don’t have their own this defined.
Now that you are convinced, you are probably writing your own arrow functions while reading this. You’ll start using them everywhere and soon your code will look cleaner than ever. But…
DON’T USE ARROW FUNCTIONS EVERYWHERE!
Wait, why? They’re cleaner, and they solved all your closure problems. Didn’t they? Well, not all of them…
If you read the first paragraph of this article you’ll see that I said arrow functions are more concise and usually a better way of describing functions. If you don’t know what you’re doing you’ll do more harm than good. Take a good look at this example:
In the example above there’s a declaration for a Array.prototype.first
method, that returns the first element in the array. If you mindlessly use arrow functions without understanding closures, you’ll end up with something like this.
The second example doesn’t work, and could lead to unpredictable results. The syntax is correct, and in theory both examples do the same thing: return the element in the first position. But since arrow functions don’t have their own this
defined, this
will reference whatever is the previous scope which could be anything from another function to the global scope or window
object.
The first example works because using the function
keyword assigns the proper scope to the function, and this
will reference the array itself correctly.
What’s the conclusion?
Arrow functions are here to stay. They make functional programming code (or any code actually) look cleaner. They solve closure problems with readable and minimal syntax. They rescue puppies from burning buildings. In short, they’re awesome.
Just one bit of advice:
When using arrow functions mind the correct use of closures, and always have in mind the scope you are working with.
Even if you always use arrow functions because they look better, never forget that they don’t solve all your problems. Sometimes going back to the basics is the better solution.