Lesson 3 · 3 of 20
Prototypes and the chain · JavaScript
See how JavaScript inheritance really works: prototypes, Object.create, constructor functions and the chain that ends in null.

In JavaScript every object has a hidden link to another object: its prototype. When you ask for a property the object does not have, the language looks in the prototype, then in that object's prototype, and so on. That lookup path is the prototype chain.
Object.create(product) creates laptop with product as its prototype. laptop only has name and price; describe is not its own (Object.hasOwn returns false), but it is found by walking up the chain. Inside describe, this is still laptop, so it prints the laptop's name and price.
Before classes existed, people used constructor functions. new User(...) creates an empty object, sets User.prototype as its prototype and runs the function with this pointing at it. Methods are added to User.prototype, so every user shares the same function: ana.greet === luis.greet is true, and it is not duplicated in memory.
If an object defines a property with the same name, it shadows the prototype's one: luis.greet has its own version while ana keeps using the shared one. The final loop walks the chain with Object.getPrototypeOf until it reaches null. Object.prototype is where methods such as toString and hasOwnProperty, available on every object, come from.
Code · main.js
const product = { describe() { return `${this.name} - ${this.price.toFixed(2)} EUR`; },};// laptop's prototype is product, so it inherits describe().const laptop = Object.create(product);laptop.name = "Laptop";laptop.price = 899;console.log(laptop.describe());console.log("Own describe?", Object.hasOwn(laptop, "describe"));console.log("Prototype is product?", Object.getPrototypeOf(laptop) === product);// Constructor functions share methods through .prototype.function User(name, role) { this.name = name; this.role = role;}User.prototype.greet = function () { return `Hi, I am ${this.name} (${this.role})`;};const ana = new User("Ana", "admin");const luis = new User("Luis", "editor");console.log(ana.greet());console.log("Same function in both?", ana.greet === luis.greet);luis.greet = () => "Luis says hello his own way"; // own property shadows the prototypeconsole.log(luis.greet(), "|", ana.greet());// The chain ends in Object.prototype, then null.const names = new Map([[User.prototype, "User.prototype"], [Object.prototype, "Object.prototype"]]);const chain = [];for (let p = Object.getPrototypeOf(ana); p; p = Object.getPrototypeOf(p)) chain.push(names.get(p));console.log("ana ->", chain.join(" -> "), "-> null");Output · node main.js
Laptop - 899.00 EUR Own describe? false Prototype is product? true Hi, I am Ana (admin) Same function in both? true Luis says hello his own way | Hi, I am Ana (admin) ana -> User.prototype -> Object.prototype -> null
Key points
- Every object has a prototype, and missing properties are looked up there.
Object.create(proto)creates an object with the prototype you choose.- Methods on
Constructor.prototypeare shared by all instances. - An own property shadows a prototype property with the same name.
- The chain ends at
Object.prototypeand thennull.
Exercise
Add an isAdmin() method to User.prototype that returns true when role is admin, and use Object.hasOwn to check that the method lives on the prototype, not on ana.