What you'll be able to do
By the end of this page you should be able to predict this from how a function is called, explain why a method “loses” this when passed as a bare callback, and know that arrow functions do not get their own this.
Previous post: AbortController with fetch. This opens Phase 9 — mental models.
Who this is for
- People who logged
thisand sawundefinedorwindow - Beginners whose button handler cannot read
this.count - Anyone scared of
thisinterviews
You can skip this if call-site rules are solid. Come back when bind is next (#61).
this is not “the function’s owner” by default
In JavaScript, this depends mainly on the call site — how you invoke the function — not where it was written.
Scenario A — method call. user.sayHi() → this is user.
Scenario B — plain call. const f = user.sayHi; f() → this is usually undefined in strict mode (modules are strict).
Method call
const user = {
name: "Asha",
sayHi: function () {
console.log("Hi, " + this.name);
},
};
user.sayHi(); // Hi, Asha
Rule: object.method() sets this to object.
Lost this in a callback
const button = document.querySelector("button");
button.addEventListener("click", user.sayHi);
// Inside sayHi, this is often the button (or undefined), not user
Scenario A — DOM handler. The browser calls your function with this = element.
Scenario B — setTimeout. setTimeout(user.sayHi, 0) also loses the method call shape.
Fixes you will use: wrap in arrow () => user.sayHi(), or .bind(user) (next post).
Arrow functions copy this from outside
const user = {
name: "Asha",
sayHi: function () {
const inner = () => console.log(this.name);
inner();
},
};
user.sayHi(); // Asha — arrow saw this from sayHi
Scenario A — nested helper inside a method. Arrows keep the method’s this.
Scenario B — arrow as object method. Often wrong for this — prefer function for methods when you want this = object.
A tiny practice file
<!DOCTYPE html>
<html>
<body>
<button id="go">Call methods</button>
<pre id="out"></pre>
<script>
const out = document.getElementById("out");
const user = {
name: "Asha",
sayHi: function () {
out.textContent += "method this.name=" + this.name + "\n";
},
};
document.getElementById("go").addEventListener("click", function () {
out.textContent = "";
user.sayHi();
const loose = user.sayHi;
try {
loose();
} catch (err) {
out.textContent += "loose call error: " + err.message + "\n";
}
document.getElementById("go").addEventListener(
"click",
function once() {
out.textContent += "handler this.id=" + this.id + "\n";
this.removeEventListener("click", once);
}
);
});
</script>
</body>
</html>
Mistakes I see a lot
1. Believing this always means “the object above the function in the file.”
2. Using arrow functions as object methods and expecting this to be the object.
3. Passing obj.method into setTimeout without wrapping/binding.
4. Mixing React class this lore with modern function components — different era; here we stay in plain JS.
What to try before the next post
- Call a method with
obj.fn()vsconst f = obj.fn; f(). - Pass a method to
addEventListenerand logthis. - Nest an arrow inside a method; compare to a nested
function.
Next in this series: call, apply, and bind — fixing lost this on purpose.
Try this next outside the series
These mental models become more useful when you can point at a real framework problem they explain.
- React Server Components explained — see execution boundaries and composition decisions in a modern app
- Node.js error handling — watch call stacks and thrown errors matter in real request code