Arrow Functions
Arrow functions, introduced in ES2015, are the modern short form for writing functions. They are not just a typing convenience — they have subtly different semantics from regular functions, and that difference is what makes them perfect for some jobs and wrong for others.
The syntax, from long to shortest
// Full form — block body, explicit return
const add = (a, b) => {
return a + b;
};
// Concise body — single expression, implicit return
const add2 = (a, b) => a + b;
// Single parameter — parentheses optional
const square = n => n * n;
// No parameters — empty parens required
const now = () => Date.now();
// Returning an object literal — wrap in parens
const point = (x, y) => ({ x, y });Arrow functions and `this`
The single biggest difference: arrow functions do not have their own this. They use the this from the surrounding scope — lexical this. That is what makes them the natural choice for callbacks.
function Counter() {
this.count = 0;
// Without arrow: `this` inside the callback would be undefined or window.
// With arrow: `this` is the Counter instance.
setInterval(() => {
this.count++;
console.log(this.count);
}, 1000);
}
new Counter();There is no way to change an arrow function's this. call, apply and bind accept a first argument, but it is silently ignored for arrows.
No `arguments`, no `new.target`, no `super`
Arrow functions also do not have their own arguments object. If you reference arguments inside an arrow, you get the enclosing function's arguments (or a ReferenceError at the top level). Use rest parameters instead.
const sum = (...nums) => nums.reduce((a, b) => a + b, 0); console.log(sum(1, 2, 3, 4)); // 10
Arrows also lack new.target and cannot use super. In practice this just means you do not use them in the places that need those features (constructors and certain class methods).
Arrows cannot be constructors
const Foo = () => {};
// new Foo(); // TypeError: Foo is not a constructorIf you need new Something(), use a regular function or a class. Arrows are for plain callable values, not for "object factories with prototypes".
When arrows are wrong
There are three places to avoid arrow functions:
Object methods that use
this.const obj = { name: "A", greet: () => this.name }—thisis notobj, it is whatever surrounds the object literal (probably the module orwindow).Constructors. Arrows cannot be called with
new.Prototype methods that need dynamic
this. Anything you want callers to be able to.call,.apply, or use as a method on another object should be a regular function.
const obj = {
name: "Ada",
greetArrow: () => "Hello " + this?.name, // undefined — wrong `this`
greetMethod() { // method shorthand — correct
return "Hello " + this.name;
},
};
console.log(obj.greetArrow()); // Hello undefined
console.log(obj.greetMethod()); // Hello AdaWhen arrows are perfect
Short callbacks:
arr.map(x => x * 2),arr.filter(x => x > 0).Inline event handlers in React/JSX where you want lexical
this.Returning a function from another function (higher-order patterns).
Any place where you read the surrounding
thisrather than wanting your own.
const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map(n => n * 2); const evens = numbers.filter(n => n % 2 === 0); const total = numbers.reduce((a, b) => a + b, 0); console.log(doubled, evens, total);
[ 2, 4, 6, 8, 10 ] [ 2, 4 ] 15