Ah yes, the infamous this keyword in JavaScript — responsible for more broken code and debugging tears than any other. In this article, we’ll laugh through the pain and explain what this actually means in different contexts.
Rule 1: this in the Global Scope
At the top level, this is the global object — window in browsers, globalThis in Node.
console.log(this === globalThis); // true in Node
Harmless here. The trouble starts when this travels.
Rule 2: this Inside a Regular Function
In a regular function, this depends on how the function is called, not where it is defined.
function greet() {
console.log(this.name);
}
const user = { name: "Alice", greet };
user.greet(); // "Alice" — called as a method, this = user
const fn = user.greet;
fn(); // undefined in strict mode — called standalone
The moment you detach the function from the object, this evaporates.
Rule 3: Arrow Functions Don’t Have Their Own this
Arrow functions capture this from the enclosing lexical scope at definition time — exactly what you want inside callbacks.
class Timer {
constructor() { this.seconds = 0; }
start() {
setInterval(() => {
this.seconds++; // `this` is the Timer instance
}, 1000);
}
}
A regular function inside setInterval would lose this entirely.
Rule 4: Explicit Binding
You can hard-wire this using .call(), .apply(), or .bind().
function introduce(greeting) {
console.log(`${greeting}, I'm ${this.name}`);
}
const person = { name: "Bob" };
introduce.call(person, "Hey"); // Hey, I'm Bob
introduce.apply(person, ["Howdy"]); // Howdy, I'm Bob
const boundIntro = introduce.bind(person);
boundIntro("Hi"); // Hi, I'm Bob
.bind() returns a new function with this permanently set — great for event handlers.
Rule 5: this in Classes
Inside a class, this refers to the instance — as long as the method is called on it.
class Dog {
constructor(name) { this.name = name; }
bark() { console.log(`${this.name} says: woof`); }
}
const rex = new Dog("Rex");
rex.bark(); // Rex says: woof
const bark = rex.bark;
bark(); // undefined — `this` is lost
Fix it with a class field arrow function:
class Dog {
bark = () => console.log(`${this.name} says: woof`);
}
Quick Reference
| How it’s called | this value |
|---|---|
| Global / standalone | globalThis (or undefined in strict) |
| As an object method | The object before the dot |
| Arrow function | Lexical this from outer scope |
.call / .apply / .bind | First argument |
new constructor | The new instance |
Takeaway
this is not broken — it is just dynamic. Once you internalize the five rules above, its behavior becomes predictable. When in doubt, use an arrow function or .bind() and move on.