Skip to main content

Command Palette

Search for a command to run...

Understanding this in JavaScript

Published
4 min read
Understanding this in JavaScript
S
Full-stack developer obsessed with performance, scalability, and clean systems. I use Arch btw.

Introduction

Most JavaScript confusion around this comes from one wrong assumption: that this depends on where a function is defined. It doesn't. It depends on who called the function.

That one shift in thinking makes most of the confusion go away.


What this Actually is

this is a reference to the calling context of a function. When a function runs, JavaScript looks at what triggered the call and sets this to that thing.

Not where the function lives in your file. Not which object it belongs to in your source code. Who called it at runtime.


this in the Global Context

When you call a plain function with nothing owning it, this falls back to the global object.

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

greet();

In a browser, that logs window. In Node.js, it's global. In strict mode, it's undefined.

Nobody specific called it, so JavaScript picks the default.


this Inside an Object

This is where this starts being useful.

const person = {
    name: 'Alice',
    greet: function () {
        console.log("Hi, I'm " + this.name);
    }
};

person.greet(); // Hi, I'm Alice

person is calling greet, so this is person. That's it.


How Calling Context Changes this

Here's the part that trips people up. Take the exact same function from above and pull it out of the object:

const greet = person.greet;
greet(); // Hi, I'm undefined

Same function. Different caller. Now nobody owns the call, this falls back to the global object, and name isn't defined there.

This is the source of most this bugs. The function didn't change. The calling context did.


this Inside Nested Functions

The problem compounds when you have a function inside a method.

const person = {
    name: 'Alice',
    greet: function () {
        function inner() {
            console.log(this.name); // undefined
        }
        inner();
    }
};

person.greet();

greet is called by person, so this inside greet is person. But inner is called as a plain function with no owner, so this resets to the global object.

A common fix is to capture this before going in:

const person = {
    name: 'Alice',
    greet: function () {
        const self = this;
        function inner() {
            console.log(self.name); // Alice
        }
        inner();
    }
};

Or just use an arrow function, which doesn't have its own this and inherits from the surrounding scope:

const person = {
    name: 'Alice',
    greet: function () {
        const inner = () => {
            console.log(this.name); // Alice
        };
        inner();
    }
};

Arrow Functions Don't Have Their Own this

Arrow functions inherit this from wherever they were defined, and nothing can change that.

const person = {
    name: 'Alice',
    greet: () => {
        console.log(this.name); // undefined, always
    }
};

person.greet();

Even though greet is on person, it's an arrow function. this here is whatever this was in the outer scope when the object was created, not person. Arrow functions are great in a lot of situations, but if you need this to refer to the object, use a regular function.


Summary

Where this appears What it refers to
Global function call Global object (or undefined in strict mode)
Object method call The object before the dot
Nested plain function Global object (loses the outer this)
Arrow function Inherited from surrounding scope

Once you internalize "who called this function," most this surprises stop being surprises. The function is the same. The caller is what changes.