Run this simple JavaScript snippet and check the output: const user = { name: "Ali", greet() {…
Run this simple JavaScript snippet and check the output:
const user = {
name: "Ali",
greet() {
console.log(this.name);
}
};
user.greet(); // "Ali"
const sayHello = user.greet;
sayHello(); // undefined
Same function. Same object.
Why did the exact same method completely forget its own data?
Here is what happens under the hood with JavaScript's "this" keyword:
1. Why Was "this" Created in the First Place?
Imagine having 500 user objects.
Hardcoding each user's variable name inside their methods creates duplicated, brittle code.
JavaScript introduced "this" as a dynamic pronoun.
Instead of hardcoding "Ali.name", a single shared function can read "this.name".
Whoever calls the function becomes "this".
2. The Rule of the Call-Site
In JavaScript, "this" is NOT determined by where a function is written.
It is determined entirely by HOW it is invoked at runtime.
The V8 engine evaluates 4 primary binding rules:
• Rule 1: Implicit Binding (Object preceding the dot)
When invoking user.greet(), the object to the left of the dot is user.
Therefore, this points directly to user.
• Rule 2: Default Binding (Standalone invocation)
When we assign const sayHello = user.greet;, we are only copying the function's memory reference, not its parent object!
Calling sayHello() is a plain, unattached invocation.
"this" falls back to the global window object (or undefined in strict mode).
Because window.name does not exist, it prints undefined.
• Rule 3: Explicit Binding (call, apply, bind)
You can manually override the caller:
sayHello.call(user); // "Ali"
sayHello.apply(user); // "Ali"
Or lock it permanently using .bind():
const boundGreet = user.greet.bind(user);
boundGreet(); // Always "Ali"
• Rule 4: Lexical Arrow Functions
Arrow functions do NOT get their own "this".
They inherit whatever "this" was in their parent lexical scope, making them ideal for modern event handlers and inline callbacks.
3. The Golden Takeaway:
Never assume a function carries its parent object around.
If it is passed as a callback or assigned to a new variable, its implicit link breaks unless you explicitly bind it or wrap it in an arrow function.
Have you ever lost the "this" context when passing methods into event listeners or React props?