Prototypes & The Prototype Chain
JS-এ inheritance prototype-chain দিয়ে চলে — class দিয়ে নয়
1. Every Object Has a Hidden [[Prototype]]
When you read a property, JS first looks at the object itself; if it isn't there, it follows the hidden prototype link to a parent object, and keeps going until it hits null. This chain is JavaScript's inheritance system.
const obj = { name: "Arif" };
console.log(Object.getPrototypeOf(obj)); // Object.prototype
console.log(Object.getPrototypeOf(Object.prototype)); // null
// __proto__ is the legacy accessor — same idea
console.log(obj.__proto__ === Object.prototype); // true
// toString comes from Object.prototype, not from obj
console.log(obj.hasOwnProperty("toString")); // false
console.log(typeof obj.toString); // "function"
[[Prototype]] link থাকে। Property পড়ার সময় আগে object-এ খোঁজা হয়, না পেলে prototype-এ — এভাবে chain ধরে শেষ পর্যন্ত null।2. The Chain — Visualized
null.
3. Object.create(proto)
const animal = {
describe() { return `I am a ${this.species}`; }
};
const cat = Object.create(animal);
cat.species = "cat";
console.log(cat.describe()); // "I am a cat"
console.log(Object.getPrototypeOf(cat) === animal); // true
// No prototype at all
const bare = Object.create(null);
console.log(typeof bare.toString); // "undefined"
4. Constructor Functions & new
Before ES6 classes, you used a regular function as a constructor. Calling it with new creates a fresh object whose prototype points to Fn.prototype.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return `Hi, ${this.name}`;
};
const p1 = new Person("Arif");
const p2 = new Person("Karim");
console.log(p1.greet(), p2.greet());
// Both share the same greet function
console.log(p1.greet === p2.greet); // true
console.log(Object.getPrototypeOf(p1) === Person.prototype);
__proto__ vs prototype
obj.__proto__ is the parent of an instance. Fn.prototype is the future parent of any instance you make with new Fn(). Two different things, easily confused.
5. instanceof & isPrototypeOf
function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
const d = new Dog();
console.log(d instanceof Dog); // true
console.log(d instanceof Animal); // true (via chain)
console.log(Animal.prototype.isPrototypeOf(d)); // true
6. Shadowing
const proto = { hello: "from proto" };
const obj = Object.create(proto);
console.log(obj.hello); // "from proto"
obj.hello = "from obj"; // shadows proto's value
console.log(obj.hello); // "from obj"
console.log(proto.hello); // "from proto" (untouched)
delete obj.hello;
console.log(obj.hello); // "from proto" again
7. Glossary (শব্দকোষ)
| Term | Meaning | বাংলায় |
|---|---|---|
[[Prototype]] | Hidden link from an object to its parent object. | Object থেকে parent-এর hidden link। |
__proto__ | Legacy accessor for an instance's prototype. | Instance-এর prototype-এর legacy accessor। |
Fn.prototype | Property on a function used as the prototype of new Fn() instances. | Function-এর প্রপার্টি — যা new Fn() instance-এর prototype হবে। |
| Prototype chain | The chain of prototypes the engine walks to find a property. | Property খুঁজতে engine যে chain ধরে এগোয়। |
Object.create | Create an object with a specified prototype. | নির্দিষ্ট prototype দিয়ে object তৈরি করার API। |
instanceof | Tests whether a constructor's prototype is in the chain. | Constructor-এর prototype chain-এ আছে কি — সেটি test করে। |
| Shadowing | Own property hides an inherited property of the same name. | Own property একই-নামের prototype property-কে ঢেকে দেয়। |
Object.hasOwn | Modern way to test if a property is the object's own (not inherited). | Property নিজের কিনা — তা চেক করার আধুনিক API। |
null। __proto__ instance-এর parent; Fn.prototype ভবিষ্যৎ instance-এর parent — দুটি আলাদা। Built-in prototype (Array.prototype) কখনোই monkey-patch করবেন না।
8. Practice Problems
- Show that
Object.getPrototypeOf({})isObject.prototype.✨ Show Answer
a1.jsconsole.log(Object.getPrototypeOf({}) === Object.prototype); - Use
Object.createto share a method across two objects.✨ Show Answer
a2.jsconst base = { say() { return `hi, ${this.name}`; } }; const a = Object.create(base); a.name = "Arif"; const b = Object.create(base); b.name = "Karim"; console.log(a.say(), b.say()); - Build a constructor function
Vehicle(type)with adescribemethod on the prototype.✨ Show Answer
a3.jsfunction Vehicle(type) { this.type = type; } Vehicle.prototype.describe = function () { return `a ${this.type}`; }; console.log(new Vehicle("car").describe()); - Verify that all instances of
Personshare the same prototype method.✨ Show Answer
a4.jsfunction Person(n) { this.n = n; } Person.prototype.say = function () { return this.n; }; const a = new Person("a"), b = new Person("b"); console.log(a.say === b.say); // true - Use
instanceofto test array vs plain object.✨ Show Answer
a5.jsconsole.log([] instanceof Array); console.log([] instanceof Object); console.log({} instanceof Array); - Inherit one constructor from another the pre-class way.
✨ Show Answer
a6.jsfunction Animal(s) { this.s = s; } Animal.prototype.describe = function () { return this.s; }; function Dog(name) { Animal.call(this, "dog"); this.name = name; } Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; const d = new Dog("Tom"); console.log(d.describe(), d.name); - Demonstrate prototype lookup by reading
arr.toString.✨ Show Answer
a7.jsconst a = [1,2,3]; console.log(a.toString()); // "1,2,3" console.log(a.hasOwnProperty("toString")); // false - Show shadowing — own property hiding a prototype property.
✨ Show Answer
a8.jsconst p = { hi: "proto" }; const o = Object.create(p); o.hi = "own"; console.log(o.hi); delete o.hi; console.log(o.hi); - Show that
Object.create(null)has no prototype (and no toString).✨ Show Answer
a9.jsconst bare = Object.create(null); console.log(Object.getPrototypeOf(bare)); // null console.log(bare.toString); // undefined - Why is monkey-patching
Array.prototypedangerous?✨ Show Answer
Answer: Adding new methods to a built-in prototype affects every array in the entire program — your code, library code, and any future feature.
for...inon an array will pick up your method as an enumerable key, breaking unrelated code. Future spec methods may collide with your name. Treat built-in prototypes as read-only. - Build a
safeobject usingObject.create(null)and put a "__proto__" key on it.✨ Show Answer
a11.jsconst safe = Object.create(null); safe["__proto__"] = "just a key"; console.log(safe["__proto__"]); // "just a key" - Detect own properties only with
Object.hasOwn.✨ Show Answer
a12.jsconst a = { x: 1 }; console.log(Object.hasOwn(a, "x")); // true console.log(Object.hasOwn(a, "toString")); // false - Override
toStringon a custom object.✨ Show Answer
a13.jsfunction Money(n) { this.n = n; } Money.prototype.toString = function () { return `৳${this.n}`; }; console.log(`Total: ${new Money(99)}`); - Compare
__proto__vsprototypein two sentences.✨ Show Answer
Answer:
obj.__proto__is the parent of an existing instance — the lookup target.Fn.prototypeis a property on the function that becomes the__proto__of any instance produced bynew Fn(). - Show that walking the chain reaches
null.✨ Show Answer
a15.jslet p = {}; while (p) { console.log(p); p = Object.getPrototypeOf(p); } - Build a tiny prototype-based mixin: copy methods from an object onto a target's prototype.
✨ Show Answer
a16.jsconst serializable = { toJSON() { return { ...this }; } }; function User(n) { this.name = n; } Object.assign(User.prototype, serializable); console.log(JSON.stringify(new User("Arif"))); - Use
Object.setPrototypeOfto change an object's parent — and explain why it's slow.✨ Show Answer
a17.jsconst base = { hi() { return "hi"; } }; const obj = {}; Object.setPrototypeOf(obj, base); console.log(obj.hi());Engines optimize property lookups by caching the object's shape. Mutating the prototype invalidates those caches and forces deoptimization — that's why
Object.createat construction is preferred tosetPrototypeOflater. - In one paragraph, explain inheritance in JS to a Java programmer.
✨ Show Answer
Answer: Java has classes — compile-time blueprints. JavaScript has only objects, but each object can link to another object as its parent through a hidden
[[Prototype]]. Method calls walk that chain at runtime; there are no compile-time class declarations under the hood. ES6classsyntax is sugar over this same chain — evenextendsjust sets up the chain viaObject.create.
Summary — Module 16
Every object has a hidden [[Prototype]] link to a parent object. Property lookup walks that chain to null. Use Object.create to set a prototype at construction; constructor functions with new link instances to Fn.prototype. Don't confuse __proto__ (instance parent) with Fn.prototype (future parent). Avoid mutating built-in prototypes.
__proto__ instance-এর parent; Fn.prototype ভবিষ্যৎ instance-এর parent। দুটি আলাদা।