Function Invocation
A function can be called in four ways — and each binds this differently. That single fact explains 80% of "why is this undefined?" questions.
The four call types
| How you call it | this becomes… |
|---|---|
fn() | undefined (strict) / window (sloppy) |
obj.fn() | The object before the dot — obj |
new Fn() | A brand-new empty object |
fn.call(x) / .apply(x, args) / .bind(x)() | Whatever you pass |
Method extraction trap
JS
const user = {
name: "Ada",
greet() { return `Hi, ${this.name}!`; },
};
user.greet(); // "Hi, Ada!" — method call, this is user
const g = user.greet;
g(); // "Hi, undefined!" — plain call, this is lost
setTimeout(user.greet, 100); // same problem — the callback is called plain
Three fixes
JS
// 1. Bind a permanent this
setTimeout(user.greet.bind(user), 100);
// 2. Wrapper preserves the call site
setTimeout(() => user.greet(), 100);
// 3. Class field as an arrow — auto-bound
class Toggle {
isOn = false;
toggle = () => this.isOn = !this.isOn; // safe to pass around
}
Constructor calls
JS
function Counter() { this.value = 0; }
new Counter(); // { value: 0 }
Counter(); // ⚠ this is undefined / window → bug
class Modern {}
Modern(); // TypeError — classes refuse plain calls (helpful!)
Tip: If you ever pass a method as a callback, either bind it or wrap it in an arrow. Modern frameworks (React with class components, vanilla event listeners) hit this exact issue all the time.
Example
Example
<!DOCTYPE html>
<html>
<body>
<p id="out"></p>
<script>
document.getElementById("out").textContent = "Hello from Function Invocation!";
</script>
</body>
</html>
Try it Yourself »
Exercise
Permanently lock greet's `this` to the user object.
const greet = user.greet.
(user);
Four letters.
Discussion
Loading…