Understanding this in JavaScript

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.



