Engrain by ByteRush

JS.03.02 Junior· 9 minCore — asked often

Arrow functions and lexical this: when to use them, and when not to

Arrow functions take this from the code around them. That fixes callbacks inside methods, breaks object methods, and costs memory as class fields.

Comes up in: JavaScript, Recruiter screen

Learn#

Jonas writes a timer object. Inside its start method he calls setTimeout(function () { this.seconds++ }). The seconds stay at 0. In the callback, this is no longer the timer.

An arrow function fixes this. Arrows do not get their own this. They use the this of the code they are written in — lexical this, found like any variable in the scope chain. The same is true for arguments, super and new.target.

const timer = {
  seconds: 0,
  startBroken() {
    setTimeout(function () { console.log("broken:", this === timer); }, 0);
  },
  startFixed() {
    setTimeout(() => { this.seconds++; console.log("fixed:", this === timer, this.seconds); }, 0);
  },
};
timer.startBroken();
timer.startFixed();

Output (verified)

broken: false
fixed: true 1

Because they have no own this, arrows cannot be used with new, and an arrow used as a method does not get the object: { go: () => this } returns the outer this.

In a DOM listener, a normal function gets the element as this; an arrow keeps the outer this. Use event.currentTarget in both cases to get the element without guessing.

Where each callback gets its thisStep 1 of 4

startFixed's this

  • timer

callback's this

  • —

Console

    empty

    timer.startFixed() is a method call, so inside startFixed, this = timer.

    Read the steps as text
    1. timer.startFixed() is a method call, so inside startFixed, this = timer.
    2. The arrow callback is created here. It has no this of its own; it will use startFixed's.
    3. Later, the timer calls the arrow plainly. That does not matter: an arrow ignores how it is called.
    4. The normal-function callback in startBroken got its this from the timer call instead — not timer.

    Predict#

    Predict first

    const shop = { name: 'Kirana', hello: () => 'Hi from ' + this?.name }; In an ES module, what does shop.hello() return?

    Interview angle#

    Say it like this — about 30 seconds

    “An arrow function has no this of its own. It uses the this of the scope it is written in, and how it is called does not change that — not even call or bind. That makes arrows ideal for callbacks inside methods. But do not use them as object or prototype methods, since they will not see the object, and they cannot be constructors. In a DOM listener, a normal function gets the element as this; with an arrow, use event.currentTarget.”

    Stays on your device. Nothing is uploaded.
    Follow-up When should you not use an arrow function?
    As an object or prototype method that needs the object, as a constructor, when you need arguments, or as a DOM handler that relies on this being the element.
    Follow-up What does this refer to inside an event listener?
    For a normal function, the element the listener is attached to (event.currentTarget). For an arrow, whatever this was where the arrow was written.
    Follow-up Can bind change an arrow's this?
    No. call, apply and bind can pass arguments to an arrow, but its this stays lexical.

    Practice#

    faded

    Fix the stopwatch’s three lost-this bugs. Hint: one is an arrow used as a method, two are normal functions used as callbacks.

    Done when

    • sw.tick() and a detached const t = sw.tick; t() both add 1 to elapsed.
    • sw.lapAll(3) records three laps.
    • sw.later(cb) calls cb with the current elapsed.
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    Where does an arrow function get its this?

    From the scope it is written in (lexical this).

    Can you call an arrow function with new?

    No — it throws a TypeError; arrows are not constructors.

    Why is an arrow a bad object method?

    It does not receive the object as this.

    How do you get the element in any event listener?

    event.currentTarget.

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    Normal functions: this comes from the call. Arrows: this comes from where they are written. Callback inside a method — arrow. The method itself — normal function.

    Check yourself: Does obj.arrow() set this to obj?

    No. Arrows ignore the receiver.

    How it works underneathSenior rounds

    Arrow functions have [[ThisMode]] lexical, so calling one never binds this; lookup goes to the outer environment instead Source: ECMA-262: ECMAScript function objects. They also have no [[Construct]], which is why new throws Source: MDN: Arrow function expressions.

    Check yourself: What is the [[ThisMode]] of an arrow function?

    lexical.

    Edge cases and trapsWhere people slip

    A method is stored once on the prototype and shared. A class field arrow, handle = () => {}, is created again for every instance:

    class Row { save() {} handle = () => {}; }
    const a = new Row(), b = new Row();
    console.log(a.save === b.save, a.handle === b.handle);

    Output (verified)

    true false

    For a few components that is fine; for 10,000 rows it is 10,000 functions.

    Check yourself: Do two instances share an arrow class field function?

    No. Each instance gets its own copy.

    In productionStaff-level answers

    Arrow class fields live on the instance, so subclasses cannot call them with super, and they are harder to mock on the prototype in tests. In React function components this problem disappears: handlers are closures, not methods.

    Check yourself: Why might an arrow class field break a subclass calling super.handle()?

    The field is on the instance, not the prototype, so super cannot find it.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • How do arrow functions handle this? When should you not use an arrow function?
    • What does this refer to inside an event listener?