The this Keyword
this is a special word that means "whoever is calling me right now" — and the tricky part is that its meaning can change every single time a function runs.
What Is this?
In most other places in JavaScript, a word means the same thing no matter where you use it. this is different. Inside a function, this refers to whatever object called that function — and that can be a different object every time the same function runs.
const user = {
name: "Maya",
greet() {
return `Hi, I'm ${this.name}`;
}
};
user.greet(); // "Hi, I'm Maya" — this.name means "the name property of whatever is left of the dot"
The key idea: this is not decided when a function is written — it's decided when a function is called. The exact same function can have a completely different this depending on how you call it.
Imagine a name tag that says "I am ___" but the blank only fills in the moment someone reads it out loud, based on who's wearing it at that exact second. Hand the same name tag to Maya, and it says "I am Maya." Hand it to Sam, and the exact same tag now says "I am Sam." The tag (the function) doesn't change — only who's currently wearing it (how it's called) changes what this means.
Rule 1: Called as an Object Method → this Is the Object
const car = {
brand: "Toyota",
describe() {
return `This is a ${this.brand}`;
}
};
car.describe(); // "This is a Toyota" — this = car, because car is left of the dot
Whatever sits directly to the left of the dot when a function is called becomes this inside that function. This is the single most common way this is used.
Rule 2: Called Alone → this Is undefined (or the Global Object)
function whoAmI() {
console.log(this);
}
whoAmI(); // undefined in strict mode / modules; the global object in old-style non-strict scripts
When a regular function is called all by itself, with nothing before the dot, there's no object to point to. Modern JavaScript (modules, classes, and anything in "use strict" mode) makes this undefined in that case, which helps catch bugs early instead of silently pointing at the browser's global window object.
Rule 3: Arrow Functions Don't Have Their Own this
const user = {
name: "Maya",
greetArrow: () => {
return `Hi, I'm ${this.name}`;
}
};
user.greetArrow(); // "Hi, I'm undefined" — arrow functions grab `this` from where they were WRITTEN, not called
This is the single biggest source of this confusion. Arrow functions never get their own this — instead, they permanently "inherit" whatever this was in the surrounding code at the moment they were defined. This is usually a problem for object methods, but incredibly useful inside callbacks (see below).
Where Arrow Functions Actually Help: Callbacks
const timer = {
seconds: 0,
start() {
setInterval(() => {
this.seconds++; // this still refers to `timer`, because arrow functions inherit `this`
console.log(this.seconds);
}, 1000);
}
};
timer.start();
If start() had used a regular function() {} inside setInterval, that inner function would be called by the timer system itself (with no object before a dot), so this would become undefined — breaking this.seconds++. The arrow function sidesteps the whole problem by never having its own this at all; it just reuses start()'s this, which correctly points to timer.
Rule 4: Explicit Binding — call(), apply(), and bind()
Sometimes you want to control exactly what this should be, rather than relying on how a function happens to get called. Three built-in methods let you set it directly:
function introduce() {
return `I'm ${this.name}`;
}
const person = { name: "Sam" };
introduce.call(person); // "I'm Sam" — runs immediately, this = person
introduce.apply(person); // "I'm Sam" — same as call, but takes arguments as an array
const boundIntroduce = introduce.bind(person);
boundIntroduce(); // "I'm Sam" — bind() doesn't run it, it returns a NEW function permanently locked to `person`
call(thisValue, arg1, arg2...)— runs the function right away, withthisset to whatever you pass in, and arguments listed one by oneapply(thisValue, [arg1, arg2])— identical tocall, but arguments are passed as a single arraybind(thisValue)— doesn't run the function at all; it hands back a brand new function withthispermanently locked, ready to be called (or passed around) later
bind() is especially common when passing a method as a callback — for example, an event handler — where it would otherwise lose track of its original object.
Rule 5: new — this Is a Brand New Object
function Dog(name) {
this.name = name; // this = the new object being built
}
const rex = new Dog("Rex");
rex.name; // "Rex"
When a function is called with new (including a class constructor), JavaScript creates a fresh, empty object first, then calls the function with this pointing at that brand new object. This is exactly how classes build this.property = value assignments inside their constructor, as covered in the Classes lessons.
Quick Reference: How this Is Decided
| How the function is called | What this becomes |
|---|---|
obj.method() | The object left of the dot (obj) |
plainFunction() | undefined (strict mode) or the global object |
func.call(x) / func.apply(x) | Whatever you explicitly pass as x |
const bound = func.bind(x) | Permanently locked to x, forever |
new Func() | The brand new object being constructed |
Arrow function () => {} | Whatever this was in the surrounding code where it was written — never its own |
Common Mistakes
- Using an arrow function for an object's method — it won't have its own
this, sothis.propertyinside it silently fails or grabs the wrong value. - Passing a method as a callback without binding it —
button.addEventListener("click", user.greet)losesuserasthis; you needuser.greet.bind(user)or an arrow-function wrapper. - Assuming
thisis decided by where a function is defined — for regular functions, it's always decided by how the function is called, which can be surprising.
Best Practices
- Use a regular
function(or method shorthand) for object methods, sothiscorrectly refers to the object. - Use arrow functions for callbacks nested inside a method, so they inherit the outer, correct
this. - Reach for
.bind()when you need to hand a method off somewhere else (like an event listener) and still wantthisto point back to the original object.
Performance Notes
Determining this has no real performance cost — it's a normal part of how a function call is set up. bind() does create a brand new function each time it's called, so avoid calling .bind() repeatedly inside a hot loop; bind once and reuse the result.
Browser Compatibility
call, apply, and function-based this rules have existed since JavaScript's earliest versions. Arrow functions and their special "no own this" behavior are newer (ES6, 2015) but supported in all current browsers.
Interview Questions
What determines the value of this inside a regular function?
How the function is called, not where it's defined — specifically, whatever object appears directly before the dot at the call site, or the object explicitly passed via call/apply/bind/new.
Why do arrow functions behave differently with this?
Arrow functions don't create their own this binding at all. Instead, they permanently use the this value from the surrounding scope where they were written, which makes them ideal for callbacks that need to reuse an outer method's this.
✏️ Exercise
Create an object counter with a count property and an increment() method that adds 1 to this.count. Call it a few times and log counter.count.
🧠 Quiz
1. Does an arrow function ever get its own this?
No — it always inherits this from the scope surrounding where it was defined.
2. What does bind() return?
A brand new function with this permanently locked to the value you provided — it does not run the function immediately.
🚀 Mini Challenge
Write an object clock with a time property and a start() method that uses setInterval with an arrow function to increase this.time by 1 every second, logging the new value each time. Explain in a comment why an arrow function is required here instead of a regular function.
Summary
thisis decided by how a function is called, not where it's written — except for arrow functions.- Object methods get
thispointing at the object before the dot; standalone calls getundefined. call/apply/bindlet you setthisexplicitly;newsets it to a freshly created object.
Related Topics
MDN reference: developer.mozilla.org → JavaScript → this (placeholder — add live link)