Understand how this is resolved dynamically, how the prototype chain works, and what classes actually add to the object model.
Open this lesson in KodokonThe value of this is decided at the call site, not at declaration time. Four rules, in decreasing priority: calling with new, explicit binding (call, apply, bind), calling as a method (obj.fn()), and a plain call (fn()), which yields undefined in strict mode. The most common real-world bug follows directly: extracting a method from its object breaks the implicit binding.
const user = {
name: "Ada",
greet() {
return "Hello, " + this.name;
},
};
console.log(user.greet()); // "Hello, Ada"
const detached = user.greet;
// detached(); // TypeError: this is undefined
const bound = user.greet.bind(user);
console.log(bound()); // "Hello, Ada"Arrow functions have no this of their own: they capture it lexically from the enclosing scope, just like a closure. That makes them ideal for callbacks, but counterproductive as methods on object literals, where this will point to the outer scope. Under the hood, every object delegates through its prototype chain: a missing property is looked up link by link until null is reached.
function Animal(name) {
this.name = name;
}
Animal.prototype.describe = function () {
return this.name + " is an animal";
};
const dog = new Animal("Rex");
console.log(dog.describe()); // "Rex is an animal"
console.log(Object.getPrototypeOf(dog) ===
Animal.prototype); // true
console.log(dog.hasOwnProperty("describe")); // falseThe class syntax does not change this model: it makes it readable. Methods declared in the class body land on Constructor.prototype and are therefore shared. Instance fields (including arrow functions assigned as fields) are recreated per instance: guaranteed this binding, but multiplied memory cost. Finally, #private fields provide privacy enforced by the engine, unlike the _underscore convention.
class BankAccount {
#balance = 0;
deposit(amount) {
if (amount <= 0) throw new Error("Invalid amount");
this.#balance += amount;
return this;
}
get balance() {
return this.#balance;
}
}
const account = new BankAccount();
account.deposit(50).deposit(25);
console.log(account.balance); // 75this during a plain call fn() with no object and no explicit binding?this?