Arrow Function Semantics
But arrow functions are much more than function expressions with a fresh coat of paint. On top of the new appearance, there are some significant differences in the way they behave too.
This post explores these new behaviours; including why arrow functions don’t have their own values for
arguments, and what that means for the code you write.
Before arrow functions, every function call would create a special variable and add it to the scope -
this equalled depended on how you called the function. Call it using
.apply(o) or as a method on
this would be equal to
Instead of adding and removing the ‘hidden’ class when the
#extra-info element is clicked, this code will result in errors being printed to the console.
In the click-handler function we pass to
this doesn’t refer to our
CollapseableSection instance. Instead, the click-handler creates it’s own value for
this, which gets set to
undefined. The inner function’s
this shadows the
this we really want, in the same way that variables defined in inner functions shadow variables of the same name defined in the outer scope.
Because arrow functions don’t create their own
this, they get to re-use the
this available in the outer scope. That leads to a neat fix to our above example:
As with most design choices, arrow functions
this-lessness comes with a downside. Since they don’t have their own
this, you can’t use them to define methods that need access to the object on which they’re called.
In regular functions,
arguments is another special variable created at call time. Its main job is to provide a list of the arguments the function was called with. This is a hugely popular feature - used to create variadic functions, functions that accept an unknown number of arguments.
For instance, as an alternative to writing a
sum function that operates on an array of numbers (i.e.
sum([1, 2, 3, 4])), you could write the following:
If you’ve not run into this before, you might be asking yourself “but what’s the
.slice.call(arguments) all about.
The issue is that
arguments has never been an array. It’s been an array-like; an object with a
.length property and numeric properties. That might not matter if you intend to use a
for(;;;) loop, but if you want to leverage the modern array methods, you’ll have to first convert to an array. That’s what the
.slice.call(arguments) trick is for.
In arrow functions, there is no
arguments created - just like there’s no
this created - when the function is called. Instead, you can use the new spread syntax to express that you want to take a variable number of arguments, and turn them into a real array.
.name property of a function to find out what they should print out for the user to see.
But we’ve seen that arrow functions are look anonymous - they don’t seem to have a name, the same way that a plain function expression doesn’t have a name when written in this form.
Of course, in conversation and in code, we think about the function as having the name
fn - the name of the variable to which it’s bound. In ES2015, whenever you create an arrow function and immediately assign it to a variable or property, the
.name variable gets set.
super keyword, tail-call optimisation, generators, and more. But hopefully this will be enough of an overview for you to see the benefits - and drawbacks - of using the new form.