Understanding Arrow Functions in JavaScript

In Brief
Arrow functions provide concise syntax and capture this from the surrounding scope rather than receiving a call‑time receiver of their own. That makes them useful for many callbacks, but a poor fit for methods that need dynamic this. They also have no own arguments object and cannot be called with new, so they are not a shorter form of every function.
JavaScript is a versatile programming language that supports various types of functions. With the introduction of ES6, arrow functions are one of the newer additions to the language that have become increasingly popular due to their conciseness and readability.
In this article, I would like to explore what arrow functions are in JavaScript, how they differ from traditional functions, and when (and how) to use them.
What are Arrow Functions?
Arrow functions, also known as "fat arrow" functions, were introduced in ECMAScript 6 (ES6) as a new syntax for creating functions in JavaScript. They are a shorthand way of defining anonymous functions in JavaScript and tend to be more readable and concise for defining function expressions than more traditional counterparts.
The basic syntax for creating an arrow function looks like this:
const sum = (a, b) => { return a + b;};In the example above we've created an arrow function called sum which accepts two parameters (a and b) and returns their sum. The arrow function is defined using the => syntax, which comes after the function's parameter list. The function's body is enclosed in curly braces {...} and contains a return statement which returns the result of the sum operation.
In this instance, this can be made even more concise by removing the braces altogether, although that isn't necessary if you feel it impedes on readability for your developers:
const sum = (a, b) => a + b;Arrow Functions vs. Traditional Functions
There are a few differences between arrow functions and traditional functions (outside of the obvious syntactical differences).
The this keyword
One of the most significant differences is the way they handle the this keyword.
In traditional functions, the value of this is determined by how the function is called. In a method call it refers to the receiver object. If a standalone function is called in a non‑strict classic browser script, this refers to window; in strict mode or an ES module, it is undefined.
On the other hand, arrow functions bind the value of this lexically. That is to say that the value of this inside an arrow function is determined by the surrounding context in which the function is defined; this inside an arrow function always refers to the value of this in the enclosing scope.
That's a lot of words that don't do a great job of describing the nuances at play, so here is an example that ‑ hopefully ‑ demonstrates the difference between traditional functions and arrow functions when it comes to the this keyword:
const name = 'Outer scope';const obj = { name: 'Brian', sayHello: function () { return `Hello, ${this.name}!`; }, sayHelloArrow: () => `Hello, ${name}!`,};console.log(obj.sayHello());//=> 'Hello, Brian!'console.log(obj.sayHelloArrow());//=> 'Hello, Outer scope!'In the above example, sayHello is a traditional function that uses method‑call this to access obj.name. sayHelloArrow is an arrow function that closes over the outer name binding directly; it does not use this at all.
When we call obj.sayHello(), method‑call this refers to obj and returns Brian. When we call obj.sayHelloArrow() the arrow closes over the outer name variable and returns Outer scope.
The arguments object
Another difference between arrow functions and traditional functions is the way they handle the arguments object. In traditional functions, the arguments object is an array‑like object that contains all the arguments passed to the function. Arrow functions do not have their arguments object. Instead, you can use the rest parameter syntax to collect all the arguments into an array.
For example:
const sum = (...args) => { return args.reduce((acc, curr) => acc + curr, 0);};console.log(sum(1, 2, 3, 4));//=> 10In the above example, we have defined an arrow function called sum which uses the rest parameter syntax (...args) to collect all the arguments passed to the function into an array. We then use the reduce method to add up all the values in the array together and return the result.
When to Use Arrow Functions
Arrow functions are a great choice for creating small, concise functions that do not require their this keyword or the arguments object. They are particularly useful when working with array methods like map, filter, and reduce.
Here are a few examples that demonstrate using arrow functions with array methods:
const numbers = [1, 2, 3, 4, 5];// using map method with arrow functionconst squaredNumbers = numbers.map(num => num ** 2);console.log(squaredNumbers); //=> [1, 4, 9, 16, 25]// using filter method with arrow functionconst evenNumbers = numbers.filter(num => num % 2 === 0);console.log(evenNumbers); //=> [2, 4]// using reduce method with arrow functionconst sumOfNumbers = numbers.reduce((acc, curr) => acc + curr, 0);console.log(sumOfNumbers); //=> 15In the above examples, we have an array of numbers numbers and we use arrow functions with the map, filter, and reduce methods to perform various operations on the array. The arrow functions used in this example are concise and readable, making the code more maintainable.
Wrapping‑Up
Arrow functions provide a more concise and readable syntax for creating functions in JavaScript. They differ from traditional functions in how they handle the this keyword and the arguments object. Arrow functions are a great choice for creating small, concise functions that do not require the use of the this keyword or the arguments object and are particularly useful when working with array methods like map, filter, and reduce.