Posts

JavaScript this and Arrow Functions Explained

JavaScript functions do not all decide this the same way. Regular functions usually get this from how they are called. Arrow functions do not create their own this at all. This post is about two questions: Where does a …

April 27, 2026 4 min read 824 words

In this article

JavaScript functions do not all decide this the same way.

Regular functions usually get this from how they are called. Arrow functions do not create their own this at all.

This post is about two questions:

  1. Where does a regular function get this from?
  2. Why does an arrow function behave differently?

this is one of the easiest JavaScript concepts to misunderstand because it looks like scope.

It is not scope.

Scope answers:

Where can this name be found?

this answers:

What object is this function running with?

Those questions are related, but they are not the same question.

Scope Is Not this

Scope is about where JavaScript looks for a name.

outer scope
+-- function scope
    +-- block scope

If code cannot find a variable in the current scope, JavaScript can look outward through the surrounding scopes.

That explains variables like name, count, or message.

this plays by a different rule.

For regular functions, this usually depends on how the function is called.

Regular Functions Get this From the Call

const user = {
  name: "Ada",
  sayName: function() {
    console.log(this.name);
  },
};

user.sayName();
// Ada

Because the function is called as user.sayName(), this points to user.

The object on the left side of the call matters.

A diagram showing user.sayName pointing this at user, while a detached sayName call has no object receiver.

user.sayName()
^^^^
this points here

Now remove that call-site.

const user = {
  name: "Ada",
  sayName: function() {
    console.log(this.name);
  },
};

const sayName = user.sayName;

sayName();
// undefined in sloppy browser scripts
// often TypeError in strict mode or modules

Same function.

Different call.

Different this.

The function did not forget about user. It was simply no longer called through user.

Arrow Functions Do Not Have Their Own this

Arrow functions are useful, but they are not regular functions with shorter syntax.

An arrow function does not create its own this.

It captures this from the surrounding lexical scope where it was created.

An arrow function does not go looking for a new this later.

It keeps the this that was already available where the arrow function was created.

That is the important correction: an arrow function is not asking the call-site for a new this.

It already has its this from where it was created.

regular function:
  this = decided when called

arrow function:
  this = borrowed from where it was created

That is the difference to keep in your head.

Arrow Functions Inside Methods

Arrow functions are often useful inside methods because they keep the method’s this.

const counter = {
  count: 0,
  start: function() {
    setTimeout(() => {
      this.count += 1;
      console.log(this.count);
    }, 1000);
  },
};

counter.start();
// 1

Here is what happens:

A diagram showing counter.start setting this to counter, then an arrow callback keeping that same this when the timer runs later.

  1. counter.start() is called.
  2. Inside start(), this is counter.
  3. The arrow function is created inside start().
  4. The arrow function captures that this.

So when the timer runs later, the arrow function still uses counter.

counter.start()
+-- this = counter
    +-- arrow callback
        +-- captures this from start()

That is the part that makes arrows helpful in callbacks.

Regular Functions Inside Methods

Compare that with a regular function.

const counter = {
  count: 0,
  start: function() {
    setTimeout(function() {
      this.count += 1;
      console.log(this.count);
    }, 1000);
  },
};

counter.start();
// not 1

The regular function passed to setTimeout gets its own this, based on how setTimeout calls it.

It does not automatically inherit this from start().

In a browser that may point at window. In Node it may be a timer object. In strict mode or module-shaped code, you may run into undefined instead.

The exact runtime detail can vary, but the core lesson does not:

A regular callback does not automatically keep the outer method’s this.

Do Not Use Arrow Functions For Object Methods

This is the other side of the rule.

const user = {
  name: "Ada",
  sayName: () => {
    console.log(this.name);
  },
};

user.sayName();
// not Ada

An arrow function does not get this from user just because it is stored as a property on user.

It captured this from the surrounding scope where the object was created.

If you want this to mean the object, use a regular method.

const user = {
  name: "Ada",
  sayName() {
    console.log(this.name);
  },
};

user.sayName();
// Ada

The method syntax above creates a regular method, so this comes from the call-site.

The Practical Rule

Keep these separate:

  • Scope answers: “Where can this name be found?”
  • Regular function this answers: “How was this function called?”
  • Arrow function this answers: “What was this where this arrow was created?”

So when you are debugging an arrow function, do not start by asking, “Who called this?”

Start by asking, “Where was this arrow function created?”

That is the question that usually gets you unstuck.

These topics build on each other:

-Rob