What is this?
Five rules. One at a time.
this is the most confusing keyword in JavaScript, and the confusion comes from one fact: its value is determined by how a function is called, not where it's defined. The same function can have a different this in different contexts. This page covers all five cases, the most common bug (losing this in callbacks), and the rule for arrow functions.
Short answer: this has five values. (1) Method call obj.fn() → this is obj. (2) Standalone call fn() → this is undefined (strict) or window (sloppy). (3) Constructor new Fn() → this is the new instance. (4) .call/.apply/.bind → this is what you pass. (5) Arrow function → this is inherited from enclosing scope. The most common bug: passing a method as a callback loses this. Fix: .bind() or an arrow wrapper.
✅ The five rules
What this is, for each way a function can be called.
Method call
obj.method() → this is obj. The most common case.
Standalone call
fn() → this is undefined (strict mode) or window (sloppy).
Constructor
new Fn() → this is the new instance. The object being constructed.
Explicit binding
fn.call(obj), fn.apply(obj), fn.bind(obj) → this is obj.
Arrow function
No own this. Inherits from the enclosing lexical scope. Set at definition time.
The bug
Passing a method as a callback detaches it from its object — this becomes undefined. Fix: .bind().
✅ The bug: losing this in callbacks
The most common this mistake in JavaScript.
const user = {
name: 'Alice',
greet() {
console.log('Hello, ' + this.name);
}
};
// ✅ Calling as a method
user.greet(); // "Hello, Alice"
// ❌ Passing as a callback
setTimeout(user.greet, 100);
// "Hello, undefined" — this is lost
// (or throws in strict mode)
// ❌ Assigning to a variable
const greet = user.greet;
greet(); // "Hello, undefined"
Why this happens: 1. user.greet() → method call. this = user. Works. 2. setTimeout(user.greet, 100) → The function is passed by reference. → setTimeout calls it as a standalone function. → this is undefined (strict) or window (sloppy). → this.name is undefined. 3. const greet = user.greet → The function is detached from user. → greet() is a standalone call. → Same problem. The function is the same. The this is different. Because this depends on HOW the function is called, not where it was defined. ❌ this is undefined inside the callback. ❌ this.name throws or returns undefined. ❌ The user object is still there — but this isn't pointing to it anymore.
✅ Three fixes
Bind, arrow wrapper, or arrow method.
const user = {
name: 'Alice',
greet() {
console.log('Hello, ' + this.name);
}
};
// ✅ Fix 1: bind
setTimeout(user.greet.bind(user), 100);
// "Hello, Alice"
// ✅ Fix 2: arrow wrapper
setTimeout(() => user.greet(), 100);
// "Hello, Alice"
// ✅ Fix 3: arrow function as the method
const user2 = {
name: 'Alice',
greet: function () {
setTimeout(() => {
console.log('Hello, ' + this.name);
}, 100);
}
};
user2.greet(); // "Hello, Alice"
Fix 1: .bind(user) → Returns a new function with this = user. → setTimeout calls the bound function. → this is always user. Works. Fix 2: () => user.greet() → Arrow function wraps the method call. → When the arrow runs, it calls user.greet() as a method. So this is user. Works. Fix 3: arrow inside the method → The outer greet is a method (this = user2). → The inner arrow captures this from greet. → When the arrow runs, this is still user2. All three work. .bind() is the most explicit. Arrow wrapper is the most common. Arrow method is the cleanest for new code. Rule: if this is lost, either bind it, or wrap it in an arrow that preserves it.
✅ Arrow functions don't have this
They inherit it from the enclosing scope.
// ❌ Arrow function as a method
const bad = {
name: 'Alice',
greet: () => {
console.log(this.name); // undefined
}
};
bad.greet(); // "undefined"
// Why: the arrow captures this from the outer
// scope (module or global), not from bad.
// ✅ Regular function as a method
const good = {
name: 'Alice',
greet() {
console.log(this.name); // "Alice"
}
};
good.greet();
// ✅ Arrow function INSIDE a method
const alsoGood = {
name: 'Alice',
greet() {
setTimeout(() => {
console.log(this.name); // "Alice"
}, 100);
}
};
alsoGood.greet();
The rule: Arrow functions do not have their own this. They inherit this from the scope where they were DEFINED, not where they are called. ❌ Arrow as a method: The arrow is defined in the module/global scope. this is captured from that scope — window or undefined. Not the object. Bug. ✅ Regular function as a method: The regular function has its own this. Determined by how it's called — as a method, this is the object. Works. ✅ Arrow inside a regular method: The outer regular function has this = object. The arrow captures that this. When the arrow runs later (in setTimeout), this is still the object. Works. Rule: arrow functions for callbacks, regular functions for methods. This is the single most common source of 'why is this undefined?' bugs.
Don't use arrow functions for object methods. They look shorter and cleaner, but they don't have their own this — they inherit it from the enclosing scope. For an object literal, the enclosing scope is the module or global scope, not the object. So this.name inside an arrow method is window.name or undefined, never the object's property. Use regular methods for objects and classes. Use arrow functions for callbacks — event handlers, setTimeout, map, filter, promise chains — where you want to preserve the outer this. This is a rule, not a style preference — the two kinds of functions behave differently.
⚠️ Common mistakes
The this mistakes that cost real time.
this is lost. Fix: .bind() or arrow wrapper.
No own this. Fix: use a regular method.
this in a nested functionThe inner function has its own this. Fix: capture with const self = this, or use an arrow.
this in strict mode functionsthis is undefined. Fix: .bind(), arrow, or pass the object explicitly.
new with a constructorWithout new, this is the global object — pollutes global scope. Fix: always use new.
this inside a handler is the element. Fix: use event.currentTarget or bind.
It captures the instance this — works, but only for the class instance, not subclasses. Fix: know the trade-off.
this is lexicalthis is dynamic for regular functions. Fix: understand the five rules.
❓ Frequently asked
What is 'this' in JavaScript?
'this' is a reference to the object that a function is being called on. Its value is determined at call time, not at definition time. There are five rules: method call — this is the object; standalone call — this is undefined (strict) or global (sloppy); constructor — this is the new instance; .call/.apply/.bind — this is the passed object; arrow functions — this is inherited from the enclosing scope.
Why is 'this' undefined in my callback?
Because when you pass a method as a callback, the method is detached from its object. It's called as a standalone function, so this is undefined (strict) or the global object (sloppy). Fixes: bind: setTimeout(obj.greet.bind(obj), 100); arrow wrapper: setTimeout(() => obj.greet(), 100).
How does 'this' work in arrow functions?
Arrow functions don't have their own this — they inherit it from the enclosing lexical scope. This is great for callbacks inside methods: array.map(item => this.process(item)) works. It's bad for object methods: const obj = { value: 1, get: () => this.value } — this inside get is the outer this, not obj. The rule: arrows for callbacks, regular functions for methods.
What is the difference between call, apply, and bind?
All three set this explicitly. call(thisArg, arg1, arg2) invokes with this = thisArg and individual arguments. apply(thisArg, [arg1, arg2]) invokes with this = thisArg and an array of arguments. bind(thisArg) returns a new function with this = thisArg permanently bound — it doesn't invoke. Use bind when you want to store the function and call it later.
What is 'this' in a class method?
In a class method, this is the instance the method is called on. But if you pass counter.increment as a callback, this is lost. Fix: class fields with arrow functions: increment = () => { this.count++; }. The arrow function captures this at construction time, so it's always the instance.
What is 'this' in the global scope?
In the browser, this at the top level is window. In Node.js, it's module.exports (or {} in ES modules). In strict mode at the top level, it's still the global object — but inside a function in strict mode, this is undefined. In modern code (modules, strict mode, classes), the most common case is this === undefined, which is why 'Cannot read property of undefined' errors are so common.
🔗 Continue learning
Next in this series: