JavaScript course menu
JavaScript Prototypes and the Prototype Chain Explained
Understand prototypes in JavaScript: how objects inherit through the prototype chain, Object.getPrototypeOf, Object.create, constructor functions and their prototype property, how classes use prototypes, own versus inherited properties, and why not to modify built-in prototypes.
On this page
Every JavaScript object has a hidden link to another object, called its prototype. When you read a property the object does not have, JavaScript looks for it on the prototype, then on the prototype's prototype, and so on. This prototype chain is how inheritance works in JavaScript, including for classes.
Where do array methods come from?#
const fruits = ["mango", "kiwi"];
console.log(Object.hasOwn(fruits, "push"));
console.log(typeof fruits.push);
console.log(Object.getPrototypeOf(fruits) === Array.prototype);
console.log(Object.hasOwn(Array.prototype, "push"));false
function
true
trueThe array itself does not have a push property. JavaScript finds it on Array.prototype, the shared object that every array links to. That is why all arrays have the same methods without each one storing a copy.
The chain#
Lookups walk up the chain until they find the property or reach null:
const fruits = ["mango"];
let level = fruits;
const chain = [];
while (level !== null) {
chain.push(level === fruits ? "fruits" : level.constructor.name + ".prototype");
level = Object.getPrototypeOf(level);
}
console.log(chain.join(" -> "), "-> null");
console.log(typeof fruits.hasOwnProperty);fruits -> Array.prototype -> Object.prototype -> null
functionhasOwnProperty comes from Object.prototype, at the top of almost every chain.
Creating an object with a chosen prototype#
Object.create(proto) makes a new object whose prototype is proto:
const animal = {
describe() {
return `${this.name} says ${this.sound}`;
},
};
const dog = Object.create(animal);
dog.name = "Bruno";
dog.sound = "woof";
console.log(dog.describe());
console.log(Object.hasOwn(dog, "describe"));
console.log(Object.getPrototypeOf(dog) === animal);Bruno says woof
false
truedescribe is found on animal through the chain, and this is still dog, the object the method was called on.
Shadowing#
If an object has its own property with the same name, it shadows the inherited one:
const defaults = { theme: "light", fontSize: 16 };
const settings = Object.create(defaults);
settings.theme = "dark";
console.log(settings.theme, settings.fontSize);
console.log(Object.keys(settings));dark 16
[ 'theme' ]Object.keys (and JSON, and spread) only include own properties.
Constructor functions#
Before classes existed, JavaScript used constructor functions. Every function has a prototype property; objects created with new link to it:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return `Hi, I am ${this.name}`;
};
const asha = new Person("Asha");
console.log(asha.greet());
console.log(Object.getPrototypeOf(asha) === Person.prototype);Hi, I am Asha
trueYou will see this style in older code and libraries.
Classes use prototypes too#
A class is a cleaner syntax for the same mechanism:
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `Hi, I am ${this.name}`;
}
}
const ravi = new Person("Ravi");
console.log(typeof Person);
console.log(Object.hasOwn(ravi, "greet"));
console.log(Object.hasOwn(Person.prototype, "greet"));function
false
trueMethods live once on Person.prototype; instances only store their own data. extends links one class's prototype to another's, which is how inheritance works.
proto#
You may see obj.__proto__ in old code; it is a legacy way to access the prototype. Use Object.getPrototypeOf(obj) and Object.setPrototypeOf(obj, proto) instead (and avoid changing prototypes of existing objects, which is slow).
Do not modify built-in prototypes#
Adding methods to Array.prototype or String.prototype affects every array or string in the program and in every library, and can clash with future JavaScript features. Some real language features had to be renamed because popular websites had added methods with the same names. Write a normal function instead.
Practice#
Practice exercise
Create a vehicle object with a method info() returning "<name> has <wheels> wheels". Create bike and car objects with Object.create(vehicle), give each a name and wheels, and print their info. Then check whether info is an own property of car.
Show solution
const vehicle = {
info() {
return `${this.name} has ${this.wheels} wheels`;
},
};
const bike = Object.create(vehicle);
bike.name = "Bike";
bike.wheels = 2;
const car = Object.create(vehicle);
car.name = "Car";
car.wheels = 4;
console.log(bike.info());
console.log(car.info());
console.log(Object.hasOwn(car, "info"));Bike has 2 wheels
Car has 4 wheels
falseKey takeaway#
Finished this lesson?