Prototypes & The Prototype Chain

JS-এ inheritance prototype-chain দিয়ে চলে — class দিয়ে নয়

~40 min Advanced 18 practice problems Live runner

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.

proto-basics.js
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"
প্রতিটি object-এর একটি hidden [[Prototype]] link থাকে। Property পড়ার সময় আগে object-এ খোঁজা হয়, না পেলে prototype-এ — এভাবে chain ধরে শেষ পর্যন্ত null।

2. The Chain — Visualized

arr = [1,2,3] own: 0,1,2,length Array.prototype map, filter, push… Object.prototype toString, hasOwn… null arr.map(...) → not on arr → looked up on Array.prototype → found! Figure 16.1 — property lookup walks the chain until found or until null.

3. Object.create(proto)

create.js
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.

ctor.js
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

instanceof.js
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

shadow.js
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 (শব্দকোষ)

TermMeaningবাংলায়
[[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.prototypeProperty on a function used as the prototype of new Fn() instances.Function-এর প্রপার্টি — যা new Fn() instance-এর prototype হবে।
Prototype chainThe chain of prototypes the engine walks to find a property.Property খুঁজতে engine যে chain ধরে এগোয়।
Object.createCreate an object with a specified prototype.নির্দিষ্ট prototype দিয়ে object তৈরি করার API।
instanceofTests whether a constructor's prototype is in the chain.Constructor-এর prototype chain-এ আছে কি — সেটি test করে।
ShadowingOwn property hides an inherited property of the same name.Own property একই-নামের prototype property-কে ঢেকে দেয়।
Object.hasOwnModern way to test if a property is the object's own (not inherited).Property নিজের কিনা — তা চেক করার আধুনিক API।
মূল ধারণা: JS-এ inheritance class-এর মাধ্যমে নয় — prototype chain-এর মাধ্যমে কাজ করে। প্রতিটি object-এর hidden parent থাকে; property পাওয়া না গেলে engine chain ধরে উপরে যায়, শেষ পর্যন্ত null। __proto__ instance-এর parent; Fn.prototype ভবিষ্যৎ instance-এর parent — দুটি আলাদা। Built-in prototype (Array.prototype) কখনোই monkey-patch করবেন না।

8. Practice Problems

  1. Show that Object.getPrototypeOf({}) is Object.prototype.
    ✨ Show Answer
    a1.js
    console.log(Object.getPrototypeOf({}) === Object.prototype);
  2. Use Object.create to share a method across two objects.
    ✨ Show Answer
    a2.js
    const 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());
  3. Build a constructor function Vehicle(type) with a describe method on the prototype.
    ✨ Show Answer
    a3.js
    function Vehicle(type) { this.type = type; }
    Vehicle.prototype.describe = function () { return `a ${this.type}`; };
    console.log(new Vehicle("car").describe());
  4. Verify that all instances of Person share the same prototype method.
    ✨ Show Answer
    a4.js
    function 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
  5. Use instanceof to test array vs plain object.
    ✨ Show Answer
    a5.js
    console.log([] instanceof Array);
    console.log([] instanceof Object);
    console.log({} instanceof Array);
  6. Inherit one constructor from another the pre-class way.
    ✨ Show Answer
    a6.js
    function 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);
  7. Demonstrate prototype lookup by reading arr.toString.
    ✨ Show Answer
    a7.js
    const a = [1,2,3];
    console.log(a.toString());  // "1,2,3"
    console.log(a.hasOwnProperty("toString"));   // false
  8. Show shadowing — own property hiding a prototype property.
    ✨ Show Answer
    a8.js
    const p = { hi: "proto" };
    const o = Object.create(p);
    o.hi = "own";
    console.log(o.hi);
    delete o.hi;
    console.log(o.hi);
  9. Show that Object.create(null) has no prototype (and no toString).
    ✨ Show Answer
    a9.js
    const bare = Object.create(null);
    console.log(Object.getPrototypeOf(bare));    // null
    console.log(bare.toString);                  // undefined
  10. Why is monkey-patching Array.prototype dangerous?
    ✨ 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...in on 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.

  11. Build a safe object using Object.create(null) and put a "__proto__" key on it.
    ✨ Show Answer
    a11.js
    const safe = Object.create(null);
    safe["__proto__"] = "just a key";
    console.log(safe["__proto__"]);     // "just a key"
  12. Detect own properties only with Object.hasOwn.
    ✨ Show Answer
    a12.js
    const a = { x: 1 };
    console.log(Object.hasOwn(a, "x"));         // true
    console.log(Object.hasOwn(a, "toString"));  // false
  13. Override toString on a custom object.
    ✨ Show Answer
    a13.js
    function Money(n) { this.n = n; }
    Money.prototype.toString = function () { return `৳${this.n}`; };
    console.log(`Total: ${new Money(99)}`);
  14. Compare __proto__ vs prototype in two sentences.
    ✨ Show Answer

    Answer: obj.__proto__ is the parent of an existing instance — the lookup target. Fn.prototype is a property on the function that becomes the __proto__ of any instance produced by new Fn().

  15. Show that walking the chain reaches null.
    ✨ Show Answer
    a15.js
    let p = {};
    while (p) {
        console.log(p);
        p = Object.getPrototypeOf(p);
    }
  16. Build a tiny prototype-based mixin: copy methods from an object onto a target's prototype.
    ✨ Show Answer
    a16.js
    const serializable = {
        toJSON() { return { ...this }; }
    };
    function User(n) { this.name = n; }
    Object.assign(User.prototype, serializable);
    console.log(JSON.stringify(new User("Arif")));
  17. Use Object.setPrototypeOf to change an object's parent — and explain why it's slow.
    ✨ Show Answer
    a17.js
    const 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.create at construction is preferred to setPrototypeOf later.

  18. 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. ES6 class syntax is sugar over this same chain — even extends just sets up the chain via Object.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.

প্রতিটি object-এর hidden parent থাকে — সেই chain দিয়ে method lookup চলে। __proto__ instance-এর parent; Fn.prototype ভবিষ্যৎ instance-এর parent। দুটি আলাদা।

Next Module → Classes & Inheritance (ES6+) — prototype-এর উপর সিনট্যাক্স sugar।