General Rule: Writes Stay Local
let animal = {
eats: true,
name: "Generic"
};
let rabbit = {
__proto__: animal
};
// WRITE - stays in rabbit, doesn't touch animal
rabbit.eats = false;
rabbit.name = "Bunny";
console.log(rabbit.eats); // false (rabbit's own property)
console.log(animal.eats); // true (animal unchanged)Exception: Getter/Setter Properties
When the prototype has a setter, writes DO go up the chain:
let user = {
_name: "John",
get name() {
return this._name;
},
set name(value) {
this._name = value.toUpperCase();
}
};
let admin = {
isAdmin: true,
__proto__: user
};
// This triggers the SETTER in user prototype!
admin.name = "alice";
console.log(admin.name); // "ALICE"
console.log(admin._name); // "ALICE" (set on admin, not user)
console.log(user._name); // "John" (user unchanged)What Happens in Your Tutorial Example:
Looking at your code:
javascript
const p1 = {
lname: "Garg",
getFullname() {
return `${this.fname} ${this.lname}`;
}
};
const p2 = Object.create(p1);
p2.__proto__.fname = "Hack"; // Direct prototype modification!This is DIRECTLY modifying the prototype object itself!
// This modifies p1 directly (the prototype object)
p2.__proto__.fname = "Hack";
// Same as writing:
p1.fname = "Hack";
console.log(p1.fname); // "Hack" (p1 was modified)
console.log(p2.fname); // "Hack" (inherited from p1)Different Ways to Write:
1. Normal property write (stays local):
javascript
let animal = { eats: true };
let rabbit = { __proto__: animal };
rabbit.eats = false; // Creates rabbit.eats, doesn't touch animal2. Direct prototype modification:
javascript
let animal = { eats: true };
let rabbit = { __proto__: animal };
rabbit.__proto__.eats = false; // Modifies animal directly!
// Same as: animal.eats = false;3. Setter in prototype (special case):
javascript
let user = {
set fullName(value) {
[this.firstName, this.lastName] = value.split(" ");
}
};
let admin = { __proto__: user };
admin.fullName = "John Doe"; // Calls setter, but this = admin
console.log(admin.firstName); // "John" (set on admin)Visual Comparison:
javascript
let parent = { x: 1 };
let child = { __proto__: parent };
// Case 1: Normal write (stays local)
child.x = 2;
console.log(child.x); // 2 (child's own property)
console.log(parent.x); // 1 (parent unchanged)
// Case 2: Direct prototype write (modifies parent)
child.__proto__.x = 3;
console.log(child.x); // 3 (now reads from parent)
console.log(parent.x); // 3 (parent was modified)The Tutorial’s Pattern Explained:
javascript
const p1 = { lname: "Garg" };
const p2 = Object.create(p1);
// Method 1: Write to p2 (stays local)
p2.fname = "Local"; // Only p2 gets fname
// Method 2: Write to prototype (modifies p1)
p2.__proto__.fname = "Shared"; // p1 gets fname, p2 inherits itWhen Writes Go Up the Chain:
✅ Writes go to prototype when:
- You explicitly write to
obj.__proto__.property - The prototype has a setter for that property
❌ Writes stay local when:
- Normal property assignment:
obj.property = value - Even if prototype has the same property name
Practical Example:
javascript
let animal = {
species: "unknown",
set species(value) {
this._species = value.toUpperCase();
},
get species() {
return this._species;
}
};
let rabbit = { __proto__: animal };
// Normal write - stays local
rabbit.age = 2;
// Setter write - calls prototype setter but this = rabbit
rabbit.species = "rabbit";
console.log(rabbit._species); // "RABBIT" (set on rabbit)
console.log(animal._species); // "unknown" (animal unchanged)
// Direct prototype write - modifies animal
rabbit.__proto__.color = "brown";
console.log(animal.color); // "brown" (animal was modified)Bottom line: Normal writes (obj.prop = val) stay local. Only setter properties or direct prototype access (obj.__proto__.prop = val) can affect the prototype chain.
