Problem Solved

JavaScript · this

Home › Courses › JavaScript › Problems › this keyword
🟨 Concept · 4 min read

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.

this-lost.js
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.

this-fixed.js
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-this.js
// ❌ 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.

1. Passing a method as a callback

this is lost. Fix: .bind() or arrow wrapper.

2. Arrow function as an object method

No own this. Fix: use a regular method.

3. this in a nested function

The inner function has its own this. Fix: capture with const self = this, or use an arrow.

4. Using this in strict mode functions

this is undefined. Fix: .bind(), arrow, or pass the object explicitly.

5. Forgetting new with a constructor

Without new, this is the global object — pollutes global scope. Fix: always use new.

6. Event handlers that need the element

this inside a handler is the element. Fix: use event.currentTarget or bind.

7. Arrow function in a class field (React)

It captures the instance this — works, but only for the class instance, not subclasses. Fix: know the trade-off.

8. Assuming this is lexical

this 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

🗺️ JavaScript learning path
The full roadmap from variables to async — every concept in order

Next in this series:

⬆️ What is hoisting?
Why you can call a function before declaring it — and why let breaks that
← All JavaScript problems
Problem solved · JavaScript