The Most Surprising Keyword
JavaScript this
`this` refers to the "context" of a function call. The rules depend on how the function is called — not where it was defined.
What you'll learn
- Identify what `this` refers to in different call styles
- Know that arrow functions don't have their own `this`
- Recognize the "lost this" callback bug
this is a special keyword inside a function. Its value depends on
how the function is called, not where it’s defined. There are
four rules.
Rule 1: Method Call
When you call a function as a method (obj.method()), this is the
object before the dot.
const user = {
name: "Ada",
greet() {
console.log(`Hi, I'm ${this.name}`);
},
};
user.greet(); // "Hi, I'm Ada" Rule 2: Plain Function Call
When you call a function on its own (not as a method), this is
undefined in strict mode (and the global object in sloppy mode).
Modules are always strict.
function greet() {
console.log(this);
}
greet(); // undefined (in strict mode / a module) Rule 3: Arrow Functions Inherit
Arrow functions don’t get their own this. They use the this
of the enclosing scope.
const user = {
name: "Ada",
greet() {
const innerArrow = () => {
console.log(`Hi, I'm ${this.name}`); // this from greet
};
innerArrow();
},
};
user.greet(); // "Hi, I'm Ada" Rule 4: new-bound
When you call a function with new, this is the brand-new object
being constructed.
function User(name) {
this.name = name; // this = the new object
}
const ada = new User("Ada");
console.log(ada); // User { name: 'Ada' } This is mostly used through class syntax, which we’ll cover next
chapter.
The “Lost this” Bug
Here’s the most common this bug. Take a method off an object and
call it standalone — this is no longer the object.
const user = {
name: "Ada",
greet() {
console.log(this?.name);
},
};
user.greet(); // "Ada" ✅ method call
const fn = user.greet;
fn(); // undefined 😱 plain call, this is undefined user.greet (without calling) gives you the function itself, no
object attached. When you later call it, you lose the connection
to user.
This bites with callbacks too:
const user = {
name: "Ada",
greet() {
console.log(this?.name);
},
};
// setTimeout calls the function as a plain function — this is lost.
setTimeout(user.greet, 10); // logs undefined
// Fix 1: wrap in an arrow that closes over user.
setTimeout(() => user.greet(), 10);
// Fix 2: bind explicitly (next lesson).
setTimeout(user.greet.bind(user), 10); Arrow Methods Misbehave
Because arrows don’t get their own this, using them AS methods
usually doesn’t work the way beginners expect.
const user = {
name: "Ada",
greet: () => {
console.log(this?.name); // this here is NOT user
},
};
user.greet(); // undefined — arrow doesn't bind to user For object methods, use regular methods (greet() { … }). For
callbacks INSIDE methods, arrow functions are great.
Cheatsheet
| How you call it | What this is |
|---|---|
obj.fn() | obj |
fn() (plain call) | undefined (in strict) |
new Fn() | new object being constructed |
Arrow () => … anywhere | inherited from enclosing scope |
Inside setTimeout(fn, ...) | undefined — fn is called plainly |
Up Next
When the default this isn’t what you want, you can set it
explicitly with call, apply, or bind.