Understanding `this` in JavaScript
How `this` is determined by how a function is called, not where it's defined.
2 min read
this is one of the most confusing parts of JavaScript because, for regular functions, its value isn't fixed by where the function is written — it's determined by how the function is called. The same function can have a different this on every call.
Method calls: 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" -- this === userStandalone function calls: this is undefined
Pull that same method out and call it on its own, and this loses its connection to user entirely:
const greet = user.greet;
greet(); // TypeError: Cannot read properties of undefinedIn strict mode (the default inside ES modules and classes), a plain function call has this set to undefined. In old-style non-strict scripts, it falls back to the global object instead — either way, it's not user anymore, because nothing about how greet() was called here ties it back to that object.
Arrow functions: this is inherited, not set
Arrow functions don't follow either rule above — they have no this of their own and instead use whatever this was in the enclosing scope when they were defined, as covered in the previous lesson:
const user = {
name: "Ada",
greetLater() {
setTimeout(() => {
console.log(`Hi, I'm ${this.name}`); // this is inherited from greetLater
}, 100);
},
};
user.greetLater(); // "Hi, I'm Ada"If greetLater used a regular function for the setTimeout callback instead, this inside it would not be user — setTimeout calls the callback with no receiver, same as the standalone call above.
Controlling this explicitly: call, apply, and bind
function greet() {
console.log(`Hi, I'm ${this.name}`);
}
const ada = { name: "Ada" };
greet.call(ada); // this = ada, args passed individually
greet.apply(ada, []); // this = ada, args passed as an array
const boundGreet = greet.bind(ada);
boundGreet(); // this = ada, permanentlycall and apply invoke the function immediately with a specific this; bind returns a new function permanently locked to that this, useful when passing a method as a callback without losing its connection to the original object.
The rule of thumb
For a regular function, ask "what's to the left of the dot when this is called?" — that's this. For an arrow function, ask "what was this in the code surrounding where this was defined?" Getting this distinction right is what makes arrow functions the correct default for callbacks that need to reference the enclosing object, and regular functions (or methods) the right choice when you specifically want this to depend on the caller.
With functions and their scoping rules covered, the next lessons turn to JavaScript's core data structures: arrays and objects.