Arrow functions

Defines a compact function expression that inherits this from the scope where it is written.

Signature
() => expression
param => expression
(param) => expression
(param1, paramN) => expression
() => {
  statements
}
param => {
  statements
}
(param1, paramN) => {
  statements
}

async param => expression
async (param1, param2, ...paramN) => {
  statements
}
  • Added in JavaScript ECMAScript 2015

Parameters

ParameterTypeDescription
$param1, …, paramNoptionalanyThe parameter names. Parentheses may be omitted for exactly one plain identifier, and rest, default and destructured parameters are all supported.
$expressionoptionalanyA single expression form whose value is returned implicitly. Wrap an object literal in parentheses so it is not read as a block.
$statementsoptionalanyA braced body, which requires an explicit return statement to produce a value.

Return value

FunctionA function object with no own this, arguments, super or new.target binding, and no prototype property.

Errors

Calling an arrow function with new throws a TypeError; using yield in its body is a SyntaxError, as is a line break between the parameter list and =>.

Changelog

  • PHP ECMAScript 2017async arrow functions were standardized alongside async/await.

Arrow functions are shorter to write and, more importantly, have no bindings of their own for this, arguments, super or new.target. Each of those resolves lexically to the enclosing scope, exactly like any other variable.

When to reach for it

  • Callbacks inside a method. this.items.map(i => this.format(i)) needs no self, no bind, no thisArg.
  • Small pure transforms passed to map, filter, sort and promise chains, where the implicit return removes most of the noise.
  • Auto-bound class handlers as class fields: handleClick = () => this.setState(...).

What trips people up

Never use one as an object-literal method. { name: "x", get: () => this.name } resolves this to whatever surrounded the object literal — the module's undefined or the global object — not to the object itself.

Returning an object needs parentheses. x => { id: x } parses as a block with a label and returns undefined; write x => ({ id: x }).

call(), apply() and bind() silently do nothing to an arrow's this. Arrows also cannot be constructed, cannot be generators, and are unsuitable as prototype methods or as DOM handlers that expect this to be the element.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Keep this pointing at the instance inside a map or forEach in a class method
  • Write a one-line comparator or predicate for sort, filter and map
  • Define an auto-bound event handler as a class field
  • Wrap an async operation in a promise chain without a self alias

Frequently asked questions

When should I not use an arrow function?

Avoid arrows for object-literal methods, prototype methods, constructors, generators, and DOM event handlers that need this to be the element — in all of those the lexical this is wrong. Use them for callbacks, small transforms and class-field handlers.

Why does my arrow function return undefined?

Most likely you wrote a block body without a return, or tried to return an object literal directly: x => { id: x } is a block containing a label, not an object. Wrap the object in parentheses — x => ({ id: x }).

Can I bind an arrow function to a different this?

No. Arrow functions have no own this binding, so call(), apply() and bind() ignore the thisArg entirely and no error is raised. If the caller must be able to choose this, use a regular function expression.

More examples

Lexical this versus a plain function

The arrow keeps the method's this and returns "obj"; the inner function expression is called with no receiver so its this is undefined and the result is undefined. The last line shows that call, apply and bind cannot retarget an arrow — all three still return "lexical".

Example · javascript
const obj = {
  label: "obj",
  viaArrow() {
    const inner = () => this.label;
    return inner();
  },
  viaFunction() {
    const inner = function () { return this?.label; };
    return inner(); // called plainly: no receiver
  },
};
console.log(obj.viaArrow(), obj.viaFunction());

const who = () => "lexical";
console.log(who.call({ id: 1 }), who.apply({ id: 1 }), who.bind({ id: 1 })());

What arrows cannot do

Arrows have no prototype property so new throws a TypeError, though name inference and length still work normally. The last pair is the classic parsing trap: wrong(1) prints undefined because the braces were read as a function body containing a labelled statement.

Example · javascript
const Arrow = () => {};
try { new Arrow(); } catch (e) { console.log("new:", e.constructor.name); }
console.log("has prototype:", "prototype" in Arrow);
console.log(Arrow.name, Arrow.length);

// Common bug: a block body looks like an object literal
const wrong = (x) => { id: x };
const right = (x) => ({ id: x });
console.log(wrong(1), right(1));

Discussion

  • Be the first to comment on this lesson.