JavaScriptArrow Functions

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

JS
// 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 });
The object-literal gotcha
`n => { id: n }` is a function with a **block body** containing a label and statement, not an object. Wrap object literals in parentheses: `n => ({ id: n })`.
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.

JS
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.

JS
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

JS
const Foo = () => {};
// new Foo();   // TypeError: Foo is not a constructor

If 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 }this is not obj, it is whatever surrounds the object literal (probably the module or window).

  • 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.

JS
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 Ada
When 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 this rather than wanting your own.

JS
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
Mental rule
If the function is **a value passed around**, use an arrow. If the function is **a method that should respect the object it lives on**, use `function` or method shorthand.