Since ES6, there are two types of general-purpose functions. One is the traditional function declared with the function
keyword. The other is the newer arrow function introduced with ES6.
In this article, we’ll look at why arrow functions are useful and when we should use them.
Defining Arrow Functions
Arrow functions are functions that have the fat arrow. For example, we can declare them as follows:
const fn = () => 'foo';
The code above will define the fn
function and return the string 'foo'
.
Multi-line functions can be written as follows:
const add = (a, b) => {
return a + b;
}
The code above adds two numbers together.
Syntactic Sugar
Arrow functions have a less verbose syntax than traditional functions. As we can see from the first example above, we can define functions in one line. Return is implicit if the function is one line.
Also, we don’t have to keep writing the function
keyword to declare functions.
We Don’t Have to Worry About ‘this’
It doesn’t have its own this
. This means that we don’t have to worry about the value of this
inside it.
This is a good thing in most cases except when we want to write class methods or constructor function methods. In all other cases, we really don’t care about this
if we use arrow functions instead of functions.
Also with traditional functions, if we want to access the value of this
inside of the outer function in the inner function, we have to access the value as follows:
In the code above, we want to access this.bar
from within the foobar
function. We have to do it by writing:
var that = this;
And in the foobar
function, we write:
console.log(that.bar);
This is a pain and it’s easy to forget.
If we use arrow functions, we can eliminate both lines and write:
This is much better since we need to write less code and we don’t have to worry about the value of this
inside the arrow function.
In addition, we can’t use bind
, apply
, or call
to change the value of this
inside an arrow function since this
can’t change inside an arrow function.
This is a nice characteristic for functions that don’t use this
, as lots of confusion is removed.
Hoisting and Function Declaration vs. Expression
There are two ways to define traditional functions in JavaScript.
One is function declaration and the other is function expression. Function declarations are loaded before any code is run, while function expressions load when the JavaScript interpreter loads the code.
An example of a function declaration is below:
function foo() {
return 1;
}
An example of a function expression is below:
const foo = function() {
return 1;
}
Since function declarations are loaded before anything else runs, they can be referenced in any part of a code file with the function declaration. This is called hoisting.
Function expressions aren’t available until the code for defining the function is run.
This difference is often overlooked and it causes confusion easily. We can remove this confusion by using arrow functions since we don’t have to worry about hoisting, function declarations, and function expressions.
With arrow functions, we can only define the functions as we did above, and it’s never available before it’s declared.
Arguments Object
Arrow functions don’t have their own arguments
object. The arguments
object is an array-like object that has all the arguments that we pass into the function call.
arguments
is an array-like object, so it has indexes, bracket notation for accessing its entries, and the length
property. And, we can loop through the items with the for
loop, but other than that, it’s nothing like an array.
This is another source of confusion since it’s kind of like an array but not really an array. With arrow functions, we can use the rest parameters instead, which does give us an array.
For instance, we can write:
const foo = (...args) => {
return args;
}
Then when we call foo
as follows:
foo(1, 2, 3, 4, 5)
We get:
[1, 2, 3, 4, 5]
Which is a real array, so we can use array methods and the spread operator with it. This is much better than the confusing arguments
object that we had to use to get dynamic parameter values, before arrow functions and the rest operator existed.
Conclusion
As we can see, arrow functions are quite useful except for using them as class methods or constructor function methods. Lots of confusion is eliminated with this
, hoisting, function declarations vs. expressions, etc.
Also, it’s much cleaner in terms of syntax since we don’t have to use the function
keyword to declare functions and return is implicit in one-line functions.
Also, we don’t have to be confused about the arguments
object anymore since arguments
doesn’t bind to arrow functions.