Skip to main content

Command Palette

Search for a command to run...

Understanding the this Keyword in JavaScript

Updated
13 min readView as Markdown

JavaScript has a special keyword called this.

At first, this can feel confusing because its value is not fixed. It can change depending on where the code is running and, most importantly, how a function is called.

A simple way to think about this is:

this is like a pronoun. Its meaning depends on the context in which it is used.

For functions, the calling context is especially important.

Let's understand it step by step.


What Does this Represent?

this is a special keyword provided by JavaScript.

It refers to a value determined by the execution context in which the code is running.

You can think of it as a hidden reference available while JavaScript executes code.

For example:

console.log(this);

The result depends on where this code is running.

This is why we should not memorize:

"this always means the current object."

That is not true.

A better rule is:

For regular functions, this is mainly determined by how the function is called.


this in the Global Context

Before understanding objects and functions, we need to understand what happens at the top level of a program.

Different JavaScript environments have different global objects.

For example:

Environment Global Object
Browser window
Node.js global
Web Worker self

JavaScript provides a standard way to access the global object regardless of the environment:

globalThis

So we can think of globalThis as:

"Give me the global object of the JavaScript environment I'm currently running in."


What Is globalThis?

globalThis is a standard JavaScript property that refers to the global object.

Instead of remembering different names such as window, global, or self, we can use:

console.log(globalThis);

For example, in a browser:

console.log(globalThis === window);

Output:

true

In Node.js:

console.log(globalThis === global);

Output:

true

So:

Browser
   │
   ├── window
   └── globalThis ──► same global object


Node.js
   │
   ├── global
   └── globalThis ──► same global object

This is an important distinction:

globalThis always refers to the global object, but this does not always refer to the global object.


Global this in the Browser

In a traditional browser script, if we write:

console.log(this);
console.log(globalThis);

we get the browser's global object:

Window { ... }
Window { ... }

And:

console.log(this === globalThis);

gives:

true

So in a normal browser script:

this
 │
 ▼
window
 │
 ▲
 │
globalThis

Here:

this === window

and:

globalThis === window

are both true.


Global this in Node.js

Node.js has an important difference.

In a CommonJS module, if we write:

console.log(this);
console.log(globalThis);

the output is conceptually:

{}
global { ... }

Why are they different?

Because a CommonJS file is wrapped by Node.js in a function.

Conceptually, Node.js does something similar to:

(function (exports, require, module, __filename, __dirname) {

    // Your code

});

The exact internal implementation is more complicated, but this simplified model helps us understand the behavior.

The wrapper is effectively called with module.exports as its this value.

Conceptually:

wrapper.call(module.exports);

Therefore, at the top level of a CommonJS module:

this === module.exports

Since module.exports starts as an empty object, we commonly see:

{}

while:

globalThis

still refers to Node's global object.

So:

Node.js CommonJS

this
 │
 ▼
module.exports
 │
 ▼
{}

globalThis
 │
 ▼
global

Therefore, in CommonJS:

console.log(this === globalThis);

is:

false

This is one of the most important differences between browser scripts and Node.js CommonJS modules.


What About Strict Mode?

Strict mode changes how this behaves inside regular functions.

Consider:

function ranveerWithNoScript() {
    return this;
}

console.log(ranveerWithNoScript());

If this regular function is called directly:

ranveerWithNoScript();

then:

Non-strict mode

In a browser, this becomes the global object:

window

In a Node.js CommonJS module, a regular function called without an explicit receiver can have this as the global object:

global

Strict mode

"use strict";

function ranveerWithNoScript() {
    return this;
}

console.log(ranveerWithNoScript());

Now:

undefined

So a useful rule is:

Regular function called directly

Non-strict mode
      │
      ├── Browser ──► window
      └── Node.js ──► global

Strict mode
      │
      └──► undefined

A Note About Top-Level this

We should be careful not to mix up top-level this with this inside a function.

For example:

console.log(this);

is top-level this.

But:

function test() {
    console.log(this);
}

test();

is this inside a function.

These can behave differently.

Also, JavaScript modules (ES modules) have different top-level this behavior from traditional scripts/CommonJS modules.

For example, in an ES module:

console.log(this);

results in:

undefined

So the environment and module system matter.

For beginners, the important lesson is:

Always consider where the code is running and whether it is a regular script, CommonJS module, or ES module.


this Inside Objects

Now let's move to the most common use of this.

Consider this object:

const actor = {
    name: "Ranveer",

    bow() {
        return `${this.name} takes a bow`;
    }
};

console.log(actor.bow());

Output:

Ranveer takes a bow

Why?

Because we called:

actor.bow();

The object on the left side of the dot is the calling object.

actor.bow()
  │
  │
  └── left of the dot
          │
          ▼
        this

So inside bow():

this === actor

Therefore:

this.name

means:

actor.name

which is:

Ranveer

The "Left of the Dot" Rule

For a beginner, this is a very useful mental model:

actor.speak();

The object before the dot becomes this for that regular method call.

actor.speak()
  │
  ▼
this = actor

Another example:

const person = {
    name: "Om",

    greet() {
        console.log(this.name);
    }
};

person.greet();

Here:

person.greet()
      │
      ▼
this = person

So:

this.name

becomes:

person.name

and prints:

Om

Calling Context Can Change this

Now comes the most important part.

The function itself does not permanently belong to the object.

Consider:

const actor = {
    name: "Ranveer",

    bow() {
        return `${this.name} takes a bow`;
    }
};

console.log(actor.bow());

Here:

actor.bow()

means:

this = actor

But now look at this:

const detachedBow = actor.bow;

console.log(detachedBow());

We copied the function into another variable and called it directly.

Now there is no:

actor.bow()

Instead, there is:

detachedBow()

So the original actor calling context is gone.

Before

actor.bow()
    │
    ▼
 this = actor


After detaching

detachedBow()
    │
    ▼
 no actor receiver
    │
    ▼
 this depends on
 strict/sloppy mode

The function body remains the same, but its calling context has changed.

This is why:

this belongs to the way a function is called, not permanently to where the function was originally written.


Regular Functions Have Their Own this

Regular functions can receive their own this binding depending on how they are called.

For example:

const myFunctionOne = function () {
    console.log(this);
};

myFunctionOne();

If called directly in non-strict mode, this can refer to the global object.

But in strict mode:

"use strict";

const myFunctionOne = function () {
    console.log(this);
};

myFunctionOne();

this will be:

undefined

So regular functions are dynamic with respect to this.


Arrow Functions Are Different

Arrow functions behave differently.

An arrow function does not create its own this binding.

Instead, it gets this from its surrounding lexical scope.

Consider:

const filmSet = {
    crew: "Spot boys",

    prepareProps() {
        console.log(`Outer this.crew: ${this.crew}`);

        function arrangeChairs() {
            console.log(`Inner this.crew: ${this.crew}`);
        }

        arrangeChairs();

        const arrangeLights = () => {
            console.log(`Arrow this.crew: ${this.crew}`);
        };

        arrangeLights();
    }
};

filmSet.prepareProps();

The output in a strict context is conceptually:

Outer this.crew: Spot boys
Inner this.crew: undefined
Arrow this.crew: Spot boys

Let's understand why.


What Happens to this in prepareProps()?

We call:

filmSet.prepareProps();

The object on the left side of the dot is:

filmSet

Therefore:

this === filmSet

inside the regular method prepareProps().

So:

this.crew

is:

filmSet.crew

which gives:

Spot boys

What Happens Inside arrangeChairs()?

Inside prepareProps() we have:

function arrangeChairs() {
    console.log(`Inner this.crew: ${this.crew}`);
}

arrangeChairs();

This is a regular function.

And it is called directly:

arrangeChairs();

There is no:

filmSet.arrangeChairs();

Therefore, it does not automatically inherit the this from prepareProps().

In strict mode:

arrangeChairs()
      │
      ▼
this = undefined

Therefore:

this.crew

does not give us "Spot boys".


What Happens Inside the Arrow Function?

Now consider:

const arrangeLights = () => {
    console.log(`Arrow this.crew: ${this.crew}`);
};

arrangeLights();

Arrow functions do not create their own this.

Instead, they lexically inherit this from their surrounding scope.

The surrounding method is:

prepareProps()

and inside that method:

this === filmSet

Therefore the arrow function also uses that this.

filmSet.prepareProps()
          │
          ▼
    this = filmSet
          │
          │ lexical inheritance
          ▼
    arrangeLights()
          │
          ▼
    this = filmSet

So:

this.crew

prints:

Spot boys

Regular Function vs Arrow Function

This gives us a very useful comparison:

Regular Function Arrow Function
Has its own this behavior Does not create its own this
this depends on how it is called this comes from surrounding scope
Can have different this values for different calls Lexically inherits this
Useful for object methods Often useful for callbacks

So:

function normalFunction() {
    console.log(this);
}

has its own this behavior.

But:

const arrowFunction = () => {
    console.log(this);
};

does not create a new this.


Another Example: Same Function, Different this

Let's make this even clearer.

const person1 = {
    name: "Om",

    greet: function () {
        console.log(this.name);
    }
};

const person2 = {
    name: "Rahul"
};

person2.greet = person1.greet;

person1.greet();
person2.greet();

Output:

Om
Rahul

Why?

The function is essentially the same:

function () {
    console.log(this.name);
}

But the calling context changes.

First:

person1.greet();

So:

this = person1

Second:

person2.greet();

So:

this = person2

The same function body can therefore work with different this values.

Same Function
      │
      ├── person1.greet()
      │       │
      │       └── this = person1
      │
      └── person2.greet()
              │
              └── this = person2

This is why thinking about the caller/calling context is so useful.


A Practical Example of Losing this

Consider:

global.name = "Gajanan Mundkar";

const obj = {
    name: "ommie",

    demo() {
        return this.name;
    }
};

const demo2 = obj.demo;

console.log(demo2());

When we call:

obj.demo();

we have:

this = obj

so:

this.name

is:

ommie

But after:

const demo2 = obj.demo;

we call:

demo2();

Now the function is detached from the object.

In non-strict mode, a direct call can make this refer to the global object.

Therefore, depending on the environment and mode, this.name can refer to the global name.

This demonstrates an important point:

Assigning an object method to another variable does not preserve the original object as this.


The Big Picture

We can summarize the major cases like this:

                         JavaScript
                             │
                             ▼
                           this
                             │
            ┌────────────────┼────────────────┐
            │                │                │
            ▼                ▼                ▼
      Global Context     Regular Function   Arrow Function
            │                │                │
            │                │                └── lexical this
            │                │
            │                └── depends on call
            │
            └── depends on environment/module type

For regular functions:

How was the function called?
          │
          ▼
Determine `this`

For arrow functions:

Where was the arrow function created?
          │
          ▼
Take `this` from surrounding scope

Quick Rules to Remember

Instead of memorizing hundreds of rules, these are the important beginner-level rules I use to reason about this.

1. this depends on context

console.log(this);

can behave differently depending on where the code runs.


2. globalThis means the global object

console.log(globalThis);

It gives you the global object of the current JavaScript environment.

Browser  → globalThis === window
Node.js  → globalThis === global

3. In a regular object method call

actor.speak();

the object before the dot is the useful mental model for this:

actor.speak()
     │
     ▼
   this

4. Detaching a method can change this

const speak = actor.speak;

speak();

The original actor is no longer the receiver of the call.


5. Regular functions have their own this behavior

function test() {
    console.log(this);
}

Its this depends on how test() is called.


6. Arrow functions don't create their own this

const test = () => {
    console.log(this);
};

They inherit this lexically from their surrounding scope.


Final Takeaway

The biggest mistake beginners make with this is thinking:

"this means the object where the function was created."

Instead, for regular functions, a better mental model is:

Look at how the function is being called.

For example:

actor.speak();
actor
  │
  ▼
 this

But:

const speak = actor.speak;

speak();

is a different call with a different calling context.

And for arrow functions:

Arrow functions don't create their own this; they inherit it from their surrounding lexical scope.

Finally, don't confuse this with globalThis.

globalThis
    │
    ▼
Global object of the environment


this
    │
    ▼
Value determined by the current context

So the easiest way to remember the whole concept is:

                    `this`
                       │
          ┌────────────┴────────────┐
          │                         │
     Regular Function          Arrow Function
          │                         │
          ▼                         ▼
   How is it called?        Where was it created?
          │                         │
          ▼                         ▼
   Calling context          Lexical surrounding scope

Once you start looking at who is calling the function and how it is being called, this becomes much less mysterious.