JavaScript Arrow Functions

Learn arrow function syntax, implicit returns, and lexical this with clear practical examples.

TL;DR

  1. Write concise callbacks using => instead of the function keyword.
  2. Skip return and braces for one-line expressions with implicit returns.
  3. Inherit this from the enclosing scope instead of redefining it.

Basic Syntax and Returning Values

    One parameter

    Drop parens when the function takes one parameter.

    const double = n => n * 2;
    double(4); // 8
    Multiple parameters

    Wrap params in parens for two or more.

    const multiply = (a, b) => a * b;
    multiply(2, 5); // 10
    No parameters

    Use empty parens for no parameters.

    const greet = () => 'Hello!';
    greet(); // "Hello!"
    Use const

    Assign with const to prevent reassignment.

    const sayHi = () => 'Hi';
    sayHi = () => 'Yo'; // throws TypeError
    Implicit return

    Drop braces and return for a single expression.

    const sum = (a, b) => a + b;
    Block body

    Use braces with return for multi-line bodies.

    const check = num => {
      return num > 10 ? 'big' : 'small';
    };
    Object literal

    Wrap object literals in parens to avoid a syntax error.

    const make = id => ({ id, active: true });

Promise and Async Patterns

    Promise chains

    Most real-world arrow functions live inside .then(), .catch(), or async wrappers.

    fetch('/api/user')
      .then(res => res.json())
      .then(data => console.log(data))
      .catch(err => console.error(err));
    Promise.all()

    Run independent async calls together and destructure results once every promise resolves.

    const loadDashboard = async () => {
      const [users, posts] = await Promise.all([
        fetch('/api/users').then(r => r.json()),
        fetch('/api/posts').then(r => r.json()),
      ]);
    };
    Async arrow

    Use an arrow function as the body of an async function for compact definitions.

    const getUser = async (id) => {
      const res = await fetch(`/users/${id}`);
      return res.json();
    };

Lexical This

    Arrow inherits this

    An arrow function inherits this from its surrounding scope, so it stays bound.

    function Timer() {
      this.count = 0;
      setInterval(() => this.count++, 1000);
    }
    Regular function this

    A regular function creates its own this, which can cause unexpected values.

    setInterval(function() {
      this.count++; // this is not the Timer
    }, 1000);
    Class methods

    This behavior makes callbacks inside class methods work without manual binding.

    class Counter {
      count = 0;
      increment = () => ++this.count;
    }
    Method callbacks

    Arrow callbacks inside a method inherit this from that method, not the caller.

    const cart = { tax: 0.1, total(p) {
      return p.map(n => n + n * this.tax);
    } };
    cart.total([100]); // [110]

Limitations

    No arguments object

    Arrow functions have no arguments object; use rest parameters to collect arguments instead.

    function legacyLogger() {
      return arguments.length;
    }
    const modernLogger = (...args) => args.length;
    No constructors

    Arrow functions cannot be used as constructors with the new keyword.

    const Person = (name) => { this.name = name; };
    new Person('Alex'); // throws: not a constructor
    No generators

    Arrow functions cannot be used as generator functions with yield.

    function* range(n) {
      for (let i = 0; i < n; i++) yield i;
    }
    [...range(3)]; // [0, 1, 2]
    No prototype

    Arrow functions have no prototype property, since they can never act as constructors.

    const Greeter = () => {};
    Greeter.prototype; // undefined

Tips

  1. Use arrow functions for short callbacks inside map() and filter(), since they keep the code easy to scan.
  2. Name longer arrow functions by assigning them to a const, since stack traces then show the variable name.

Warnings

  1. Do not use arrow functions as methods on objects when those methods need access to the object through this.
  2. Arrow functions cannot be used as constructors, so calling one with new throws a TypeError instead of creating an instance.

In Practice

FAQ