When not to use Arrow Function
This post was originally published here on May 16, 2017
Arrow Functions
With ECMAScript2015 or otherwise called ES6, arrow-function was introduced. The goal of arrow function is to make functions in javascript to be developer-friendly and easy to eyes. But as you may already aware they are just syntactic sugar to function nothing more. Arrow function made following as things of past when used,
- no need to explicitly state the function keyword
- no need of curly brackets
- no need for the return keyword when one line function
But while making it simpler it also made them vague, most probably when it comes to this
keyword. It did reduce the complexity surrounded in JavaScript’s function scope. In arrow-function this
refers to the immediate outer scope of the function instead of function scope itself. We will dive deep into this in a minute
Arrow function simplified is just an anonymous immutable function to have some kind of certainty of results for the given input. Similar to functional programming languages where variables states as assigned initially are immutable
All that being said, arrow functions are not a one-size-fits-all solution for every need you will encounter when writing JavaScript functions. Let’s dive into a few situations in which arrow functions are not the right answer.
Methods
Let’s say you want to create a method to bind to an object.
const display = {
size: 100,
increaseSize: () => {
this.size += 10;
}
}
In this example, if we call display.increaseSize()
, we expect the value of `display.size` to increase from 100 to 110. However, as currently written, the value of size
will remain unchanged regardless of how many times increaseSize()
is called. Why is this? The answer is this
! As MDN states:
An arrow function does not have its own
this
. Thethis
value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching forthis
which is not present in current scope, an arrow function ends up finding thethis
from its enclosing scope.
In our case, when this is executed in the browser console, the enclosing scope would be the window
object. Invoking increaseSize()
would be asking the program to increment the value of size
in the window
object. No such value exists, so the code does not work.
Instead, we want to use traditional function syntax, which will bind the function’s this
to the specific object calling the function:
Dynamic Context
By dynamic context I mean, attaching an arrow function to dynamically execute when something happens, meaning binding it to an event. Since this would still point to the lexical immediate outer scope of function, resulting this pointing to window
object when referenced. Following code will not work as expected
someButton.addEventListener('click', () => {
this.doSomething();
}
While being a seasoned JavaScript programmer, one may think this would invoke a function defined on someButton
object, but no, it would instead look for doSomething
to be defined in the outer scope
When manipulating the DOM via event handlers or listeners, triggered events point to the this
belonging to the targeted element.
Bind
While we have already seen how this
works differently in arrow-functions, to add to our dismay and confusion, bind
also is not made available to arrow-function. If one tries to bind a scope to an arrow-function, it would result in TypeError
As always, thanks for reading