Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
JavaScriptDevelopmentTutorial

JavaScript arrow functions: syntax, this, and when not to use them

Every arrow function syntax form, how arrow functions take this from the surrounding code, what they cannot do, and the places a regular function or method is still the right choice.

Cloudsoft Zone

Updated 6 min read

Close-up of colourful JavaScript and HTML source code on a dark editor screen, with the Cloudsoft Zone logo in the corner
In this article

JavaScript arrow functions are shorter, but behaviour is the real difference. This guide covers every syntax form, how arrow function this comes from the surrounding code, what arrows cannot do and when to choose an arrow function vs regular function for methods, classes and DOM events.

An arrow function is a shorter way to write a function expression: (a, b) => a + b. The shorter syntax is the obvious difference, but the important one is behaviour: an arrow function has no this, arguments or prototype of its own and cannot be called with new. It uses the this of the code around it. That makes arrows ideal for callbacks and wrong for object methods, and most arrow-function bugs come from mixing those two up.

Tested with Node.js 24.19.0 (V8 13.6). Every result shown in a comment was printed by running the code; the same code runs in current Chrome, Firefox and Safari.

Arrow functions arrived in ES6 (ECMAScript 2015). They are used most as short callbacks, such as items.forEach((item) => console.log(item.name)) or prices.map((price) => price * 1.2), and as event handlers inside classes and components.

Arrow function syntax, every form

JavaScript
const add = (a, b) => a + b;          // two parameters, implicit return
const double = n => n * 2;             // one parameter: parentheses optional
const now = () => Date.now();          // no parameters: empty parentheses required
const area = ({ width, height }) => width * height; // destructured parameter
const greet = (name = 'there') => `Hello, ${name}`; // default value
const load = async (url) => (await fetch(url)).json(); // async arrow

const total = (items) => {             // a block body needs an explicit return
  const sum = items.reduce((acc, item) => acc + item.price, 0);
  return Math.round(sum * 100) / 100;
};

Two syntax rules catch people out:

  • Returning an object literal needs parentheses. In () => { id: 1 } the braces are read as a function body and id: as a label, so the function returns undefined. Write () => ({ id: 1 }).
  • The arrow must be on the same line as the parameters. A line break between (a, b) and => is a syntax error; a line break after => is fine.

How this works in an arrow function

A regular function gets its this from how it is called: obj.method() sets it to obj, a plain call leaves it undefined in strict code, and a timer or event callback gets whatever the caller passes. An arrow function ignores all of that and keeps the this of the function it was written in. This is called lexical this.

JavaScript
const counter = {
  count: 0,
  startRegular() {
    setTimeout(function () {
      console.log(this === counter); // false: a regular callback gets its own this
    }, 0);
  },
  startArrow() {
    setTimeout(() => {
      this.count++;
      console.log(this.count); // 1: the arrow uses start's this, the counter
    }, 0);
  },
};
counter.startRegular();
counter.startArrow();

Before arrow functions this needed const self = this or .bind(this). Inside class methods, array callbacks, promise chains and timers, an arrow function is now the simplest correct choice.

Because the binding is fixed when the arrow is created, call, apply and bind cannot change an arrow's this: they still pass the arguments, but the first argument is ignored.

What arrow functions cannot do

JavaScript
const user = {
  name: 'Asha',
  greetArrow: () => `Hi ${this?.name}`,
  greet() { return `Hi ${this.name}`; },
};
console.log(user.greetArrow()); // Hi undefined: this is the module's this, not user
console.log(user.greet());      // Hi Asha

const Point = (x, y) => ({ x, y });
try { new Point(1, 2); } catch (e) { console.log(e.constructor.name, e.message); } // TypeError Point is not a constructor
console.log(Point.prototype); // undefined

const sum = (...numbers) => numbers.reduce((total, n) => total + n, 0);
console.log(sum(1, 2, 3)); // 6

const wrong = () => { id: 1 };
const right = () => ({ id: 1 });
console.log(wrong(), right()); // undefined { id: 1 }
  • No own this: an arrow written as an object property does not see the object. Use method shorthand, greet() { … }, for anything that reads this.
  • No arguments: use rest parameters, (...numbers), which give a real array.
  • No new and no prototype: arrows cannot be constructors. Use a class.
  • No super of their own and no yield: an arrow cannot be a generator.

Arrow functions in classes: fields versus methods

An arrow function assigned to a class field is created once per instance and keeps that instance as this, even when the function is passed around on its own. A normal method lives once on the prototype and loses this when it is detached:

JavaScript
class Timer {
  seconds = 0;
  tick = () => { this.seconds++; }; // a class field: bound to each instance
  reset() { this.seconds = 0; }      // a method: shared on the prototype
}
const timer = new Timer();
const { tick, reset } = timer;
tick();
console.log(timer.seconds); // 1
try { reset(); } catch (e) { console.log(e.constructor.name); } // TypeError: this is undefined
console.log(Object.hasOwn(timer, 'tick'), Object.hasOwn(timer, 'reset')); // true false

Use an arrow field for a function you will hand to someone else, such as an event listener you need to remove later with the same reference. Use normal methods for everything else: they are shared by all instances, appear on the prototype for subclasses to override with super, and cost less memory when you create many objects.

Arrow functions and DOM events

In a listener written as a regular function, this is the element the listener is attached to. In an arrow it is not, so read the element from the event instead, which works with both forms:

JavaScript
button.addEventListener('click', (event) => {
  event.currentTarget.classList.toggle('is-active'); // the button, whatever this is
});

When to use arrow functions, and when not to

SituationUseWhy
Array callbacks: map, filter, reduce, sortArrowShort, and no this needed
Callbacks inside a method: timers, promises, listenersArrowKeeps the method's this
Object methods that read thisMethod shorthandAn arrow would not see the object
Class methodsMethodShared on the prototype; overridable
A class callback passed elsewhereArrow fieldBound to the instance
Constructors and generatorsClass or function*Arrows cannot do either
Top-level named functionsEitherfunction declarations are hoisted; const arrows are not

The last row is a style choice. A function declaration can be called before the line that defines it, while calling a const arrow early throws a ReferenceError. Many teams prefer declarations for named top-level functions because stack traces and reading order are clearer, and arrows for everything passed as a value.

Arrow functions in interviews

The most common interview questions here are what this is inside an arrow (the surrounding function's), why user.greetArrow() above prints undefined, and how to rewrite an arguments-based function with rest parameters. Our JavaScript interview questions and answers covers these alongside closures and the event loop.

Frequently asked questions

  • What is the difference between an arrow function and a regular function?

    An arrow function has no this, arguments, super or prototype of its own: it uses the this of the surrounding code and cannot be called with new or be a generator. A regular function gets this from how it is called.

  • Why does my arrow function return undefined when I return an object?

    In () => { id: 1 } the braces are a function body, not an object. Wrap the object in parentheses: () => ({ id: 1 }).

  • Can I use an arrow function as an object method?

    Only if it never reads this. An arrow written as an object property takes this from the surrounding scope, not from the object, so use method shorthand such as greet() { return this.name; }.

  • Can bind, call or apply change this in an arrow function?

    No. An arrow function's this is fixed when it is created. call and apply still pass the other arguments, but the this value you give them is ignored.

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. Arrow function expressions — MDN Web Docs
  2. this — MDN Web Docs
  3. Public class fields — MDN Web Docs
  4. Rest parameters — MDN Web Docs
  5. ECMAScript 2025 Language Specification: Arrow Function Definitions — Ecma International TC39

Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.

Comments

No comments yet. Be the first to join the conversation.

Leave a comment

Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.