JavaScript Arrow Functions
This article explains what JavaScript arrow functions (also known as arrow function expressions) introduced in ES6 (ES2015) are. It covers how to use arrow functions, the key differences between arrow functions and regular functions, and the reasons to use them.
Background of JavaScript Arrow Functions
The term arrow function is also officially known as arrow function expressions. Both terms are used interchangeably, but in this article, we will refer to them simply as arrow functions.
JavaScript arrow functions were introduced in ECMAScript 6 (ES6). ES6, published in 2015, is the sixth edition of the ECMAScript standard, which includes various new features and improvements.
Arrow functions were designed to provide a more concise and easier way to write functions compared to traditional function declarations and function expressions used in JavaScript. They are inspired by the concept of lambda functions found in languages like C++, Python, and Java, adapted into JavaScript syntax. By introducing arrow functions, JavaScript embraced a stronger functional programming style, allowing developers to write code that is more concise and easier to read.
However, arrow functions have some limitations and are not suitable for all use cases. (The following points are summarized from MDN - Arrow function expressions.)
Limitations of Arrow Functions
- They do not have their own binding of
this
,arguments
, orsuper
, so they should not be used as methods. - The
new.target
keyword is not available. - The usual methods for setting scope—
call()
,apply()
, andbind()
—cannot be used with arrow functions. - They cannot be used as constructor functions.
- The
yield
keyword cannot be used inside arrow functions.
While these limitations may seem like disadvantages, they can also be considered advantages depending on the context of using arrow functions.
How to Use Arrow Functions
This section explains how to define arrow functions in JavaScript and the syntax and formatting used to write them.
Defining Arrow Functions
In JavaScript, arrow functions are a type of function expression assigned to variables. They cannot be defined using function declarations.
function add(a, b) {
return a + b;
};
add(1, 2); // 3
const add = function(a, b) {
return a + b;
};
add(1, 2); // 3
const add = (a, b) => {
return a + b;
};
add(1, 2); // 3
Arrow functions use the =>
symbol (arrow) instead of the function
keyword, enabling simpler and more concise function expressions compared to traditional functions.
Special Syntax of Arrow Functions
Compared to regular functions, arrow functions have some unique syntax rules:
- When there is a single parameter, parentheses
()
can be omitted. - If the function body consists of a single expression, the
return
keyword can be omitted. In this case, curly braces{}
must also be omitted. - Duplicate parameter names are not allowed.
Omitting parentheses when there is a single parameter
// Parentheses are optional when there is only one parameter.
const func = param => { ... }; // Parentheses omitted
// This is equivalent to:
const func = (param) => { ... }; // Parentheses included
Note:
If there are no parameters, parentheses ()
cannot be omitted.
Omitting the return
keyword for single-expression function bodies
const add = (a, b) => a + b; // When omitting <code>return</code>, curly braces must be omitted as well.
// This is equivalent to:
const add = (a, b) => { return a + b; };
Note:
If the function body is not a single expression, the return
keyword cannot be omitted.
const add = (a, b) => {
const sum = a + b;
console.log("Sum:", sum);
// <code>return</code> cannot be omitted here.
return sum;
};
const result = add(3, 5);
console.log("Result:", result); // Output: Sum: 8, Result: 8
Duplicate parameter names are not allowed
// Incorrect usage: duplicate parameter names
const multiply = (x, y, x) => {
return x * y;
};
In regular functions without strict mode, JavaScript engines do not throw an error for duplicate parameter names.
However, arrow functions do not allow declaring duplicate parameter names, regardless of strict mode.
Differences Between Arrow Functions and Regular Functions
Beyond the syntactic differences discussed earlier, this section covers some important distinctions between arrow functions and regular functions. We focus on key points you should be aware of.
Key Differences from Regular Functions
- Arrow functions cannot be used as constructors and cannot create instances.
- Arrow functions do not have their own
this
binding. - Arrow functions do not have their own
arguments
object.
Arrow Functions Cannot Be Used as Constructors
const Person = (name) => {
this.name = name;
};
const john = new Person("John"); // Error: Person is not a constructor
Arrow functions differ from regular functions in that they cannot create instances because they are non-constructors. This means they have no prototype
property and do not create a prototype.
const Person = (name) => {
this.name = name;
};
console.log(Person.hasOwnProperty("prototype")); // false
Arrow Functions Do Not Have Their Own this
Binding
<!DOCTYPE html>
<html>
<head>
<title>Event Listener Example</title>
</head>
<body>
<button id="myButton">Click Me</button>
<script src="event.js"></script>
</body>
</html>
// event.js
const myButton = document.getElementById('myButton');
// Event handler using a regular function
myButton.addEventListener("click", function() {
console.log("Clicked using normal function. This: " + this.textContent);
});
// Event handler using an arrow function
myButton.addEventListener("click", () => {
console.log("Clicked using arrow function. This text: " + this.textContent);
});
When handling events using addEventListener
, the value of this
inside the callback typically refers to the DOM element that triggered the event.
However, the this
context differs depending on whether you use a regular function or an arrow function.
In the example above, two event handlers are attached to the myButton
element. The first uses a regular function, and the second uses an arrow function.
When clicking the button, both handlers run.
The first handler's this
refers to the myButton
element, so this.textContent
outputs "Click Me."
The second handler, however, uses an arrow function. When clicked, it outputs:
"Clicked using arrow function. This text: undefined"
This happens because arrow functions do not have their own this
and instead inherit this
from the surrounding (lexical) scope, which in this case is the global context, where this.textContent
is undefined.
Therefore, when you need to use this
inside event handlers, it's best to use regular functions. Arrow functions are useful when you want to avoid creating a new this
context and prefer to use the this
from the outer scope.
Arrow Functions Do Not Have Their Own arguments
Object
function sumWithArguments() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
const sumWithArrow = () => {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i]; // Error: arguments is not defined
}
return sum;
}
console.log(sumWithArguments(1, 2, 3, 4, 5)); // Output: 15
console.log(sumWithArrow(1, 2, 3, 4, 5)); // Error: arguments is not defined
The arguments
object provides access to the function's arguments in regular functions. However, arrow functions do not have their own arguments
object.
In the example, sumWithArguments
is a regular function that uses arguments
to calculate the sum of all passed arguments. In contrast, sumWithArrow
is an arrow function, and trying to use arguments
inside it causes an error.
Therefore, if you need to access the arguments object, prefer regular functions over arrow functions.
Why Use Arrow Functions
Compared to traditional functions, arrow functions allow you to write more concise and readable code using a shorter syntax.
Many developers prefer writing compact code, especially for callbacks or inline functions.
Another major reason to use arrow functions is how they handle the this
keyword. Unlike regular functions, arrow functions do not have their own this
; instead, they inherit it from the enclosing (lexical) scope.
This behavior helps avoid common this
-related issues in JavaScript, especially inside methods. Let’s look at an example.
const myObj = {
name: "John Doe",
func: function() {
console.log(this.name); // Output: "John Doe"
// Using a regular function
setTimeout(function() {
console.log(this); // Output: window (or global object in Node.js)
console.log(this.name); // Output: undefined
}, 1000);
// Using bind() with a regular function
setTimeout(function() {
console.log(this); // Output: myObj
console.log(this.name); // Output: "John Doe"
}.bind(this), 1000);
},
arrow_func: function() {
console.log(this.name); // Output: "John Doe"
// Using an arrow function
setTimeout(() => {
console.log(this); // Output: myObj
console.log(this.name); // Output: "John Doe"
}, 1000);
}
};
myObj.func();
myObj.arrow_func();
Analysis
- In the
func()
method, the firstsetTimeout
uses a regular function, which creates its ownthis
.
As a result,this
refers to the global object andthis.name
becomesundefined
. - The second
setTimeout
insidefunc()
uses.bind(this)
to explicitly bind the correctthis
value to the callback, but this adds unnecessary complexity. - In contrast, the
arrow_func()
method uses an arrow function insidesetTimeout
.
Here,this
is lexically inherited from the enclosing function (arrow_func
), which is bound tomyObj
.
As a result, there's no need forbind()
, and the code remains simpler and more readable.
Summary
Using arrow functions can help you avoid the hassle of manually binding this
in many scenarios, particularly when working with methods and callbacks.
However, it’s important to understand that arrow functions are not a universal replacement. In some cases, regular functions—with their own this
context—are more suitable.
As with most things in programming, the key is to choose the right tool for the job.
Specifications
Specification | |
---|---|
Arrow Function Definitions |
ECMAScript Language Specification #sec-arrow-function-definitions |
Browser compatibility
Syntax |
Desktop Chrome
|
DesktopDesktop Edge
|
Desktop Firefox
|
Safari
|
---|---|---|---|---|
Arrow functions
|
45 | 12 | 22 | 10 |