JavaScript Arrow Functions
Learn how JavaScript arrow functions work: lexical this, no own arguments or super, and why they can't be constructors.
Introduction to JavaScript Arrow Functions
Arrow functions, introduced in ES6 (ECMAScript 2015), are now a key feature in JavaScript, providing a simpler way to write function expressions. They are particularly popular because they make things easier and help solve common problems with the this keyword.
This page goes beyond the syntax (covered in Arrow functions, the basics) and digs into why arrow functions behave the way they do. The short version is that an arrow function has no bindings of its own. It doesn't get its own this, its own arguments, its own super, or a [[Construct]] method. Whenever you reference any of these inside an arrow, JavaScript looks them up in the surrounding (lexical) scope, exactly as it would for any ordinary variable. Almost every quirk and every advantage of arrow functions follows from that one rule.
Defining Arrow Functions
Arrow functions allow for shorter syntax compared to traditional function expressions. Here's a basic comparison to demonstrate:
The arrow function version is not only shorter but also eliminates the need for the function keyword and braces when there's a single expression.
Syntax Variations
Arrow functions can be written in various forms depending on the number of parameters and the complexity of the function body:
- No Parameters: Use empty parentheses:
- Single Parameter: Parentheses are optional:
- Multiple Parameters: Parentheses are required:
- Multiple Lines: Use curly braces and an explicit
return(if it returns a value):
Arrow Functions Have No Own this
The most important property of arrow functions is that they don't get their own this. A regular function decides its this at call time based on how it is called (covered in Object methods, "this"). An arrow function ignores all of that and reads this from the scope where it was defined — this is called lexical this.
This is exactly what you want when an arrow runs as a callback. A method that loses its this inside an ordinary callback keeps it inside an arrow:
Replace the arrow with a regular function(member) { ... } and this inside forEach becomes undefined, throwing Cannot read properties of undefined. Before arrow functions, developers worked around this with const self = this; or .bind(this) — see Function binding. Arrow functions remove the need for those tricks.
The same lexical rule fixes the classic timer problem, where a callback runs detached from its object:
Because this is fixed lexically, you cannot change it. Calling .call(), .apply(), or .bind() on an arrow function has no effect on this — the binding is ignored:
Arrow Functions Have No arguments
Arrow functions also have no arguments object of their own. Referencing arguments inside an arrow reaches into the enclosing function — which is handy for wrappers and decorators:
If you actually need the arguments of the arrow function itself, use rest parameters (...args), which work everywhere:
Arrow Functions Are Not Constructable
Since an arrow function has no [[Construct]] internal method and no prototype property, you cannot use it with the new operator:
For the same reason, arrow functions cannot reference super to reach a parent class, so they're never used as class constructors or class methods that rely on super.
When Not to Use Arrow Functions
Lexical this is great in callbacks but wrong in a few common places. Reach for a regular function when the function needs its own dynamic this.
Object Methods
When a function is the method of an object, you usually want this to point at that object. An arrow takes this from the outer scope instead (often the module or global scope), so it won't see the object's own properties:
Use the regular method shorthand (or a function expression) for object methods. See Object methods, "this" for the full picture.
Prototype Methods and Constructors
Because arrows aren't constructable and have no own this, they can't define prototype methods or serve as constructor functions. Methods added to a prototype must be regular functions so each instance resolves this to itself.
DOM Event Handlers (in the browser)
When you attach a handler with addEventListener, the browser calls it with this set to the element that received the event. An arrow ignores that and keeps the outer this, so use a regular function if you need this to be the element (you can always use event.currentTarget either way).
Advanced Techniques
Returning Object Literals
To return an object literal from an arrow function, wrap the object in parentheses:
IIFE with Arrow Functions
Arrow functions can be used for Immediately Invoked Function Expressions (IIFE):
Summary
Arrow functions are best understood by what they lack. They have:
- No own
this— it's taken from the surrounding scope (lexicalthis), and.call/.apply/.bindcan't change it. Ideal for callbacks, wrong for object methods. - No own
arguments— use rest parameters (...args) if you need them. - No
super— so they can't be class methods that call a parent. - No
[[Construct]]and noprototype— so they can't be used withnewor as prototype methods.
Use arrows for short callbacks and any function that should keep its outer this. Use regular functions for object methods, prototype methods, constructors, and DOM handlers that need a dynamic this.
Related Chapters
- Arrow functions, the basics
- Object methods, "this"
- Function binding
- Constructor, operator "new"
- Rest parameters and spread syntax