JS Prototype & OOP
The Prototype Chain
Every object has an internal [[Prototype]] link to another object. Accessing a missing property walks up this chain until found or null is reached.
const animal = { breathes: true };
const dog = Object.create(animal); // dog.__proto__ === animal
dog.name = "Rex";
dog.name // "Rex" — own property
dog.breathes // true — found on the prototype
dog.toString // function — found further up, on Object.prototype
dog.breathes = false; // WRITES always create an OWN property — never mutates the prototype
animal.breathes; // still true — untouched
Prototypal vs. Classical Inheritance
Classical (Java/C++): classes are blueprints, objects are instances, inheritance via extends. Prototypal (JS): objects inherit directly from other objects via the prototype chain — class syntax is syntactic sugar over this same underlying mechanism, not a genuinely different inheritance model.
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks`; }
}
const d = new Dog("Rex");
d.speak(); // "Rex barks"
d instanceof Dog && d instanceof Animal; // true, true
Object.getPrototypeOf(d) === Dog.prototype; // true — confirms class syntax IS the prototype chain
Objects Are Reference Types
const a = { x: 1 };
const b = a; // b is the SAME object, not a copy
b.x = 2;
a.x; // 2 — mutating through b affects a
This is the JS instance of the general reference-semantics discussion in [[Identity, Mutability & Memory]] (Python) — the underlying concept (mutable reference types vs. copied primitives) recurs across languages, only the specific syntax differs.
Function Declaration vs. Expression
function add(a, b) { return a + b; } // declaration — fully hoisted, callable before this line
const add = function(a, b) { return a + b; }; // expression — NOT hoisted as a callable function
const add = (a, b) => a + b; // arrow expression — also not hoisted, no own `this`
localStorage / sessionStorage / Cookies
localStorage | sessionStorage | Cookies | |
|---|---|---|---|
| Capacity | ~5MB | ~5MB | ~4KB |
| Expiry | Never (until cleared) | Tab/session close | Configurable |
| Sent to server | No | No | Yes, on every request |
| Scope | Origin | Origin + tab | Domain + path |
Only cookies are automatically sent with every HTTP request — this is precisely why session tokens historically lived in cookies (server needs to see them without extra client-side wiring) and why localStorage is the wrong place for anything the server needs on every request without an explicit header.
Interview Drills
- What does
Object.getPrototypeOf(instance) === MyClass.prototypeconfirm about JSclasssyntax? — Thatclassis genuinely implemented as prototypal inheritance underneath — an instance's prototype IS the class's.prototypeobject, the same mechanism as manually chaining objects withObject.create(), not a separate classical-inheritance system bolted on top. - Why does
dog.breathes = falsenot affect theanimalobject it inheritsbreathesfrom? — Writing a property always creates (or updates) an own property directly on the target object — the prototype chain is only consulted on reads for properties the object doesn't have itself; a write never walks up the chain to mutate an inherited property's source. - Why would you choose a cookie over localStorage for an auth session token in a traditional server-rendered app? — Cookies are automatically included in every HTTP request to the matching domain, which is exactly what a server needs to authenticate incoming requests without any additional client-side code to attach a token manually —
localStoragerequires the client to explicitly read and attach the value to each request itself.
Cross-links
[[JS Core Language & Data Types]] · [[JS Closures & Async]] · [[Python OOP & Data Model]] · [[SOLID Principles]]