Skip to content
Laviyx Learn

Try

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.

Advanced8 min readUpdated
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?#

JavaScript
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"));
Output
false
function
true
true

The 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:

JavaScript
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);
Output
fruits -> Array.prototype -> Object.prototype -> null
function

hasOwnProperty 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:

JavaScript
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);
Output
Bruno says woof
false
true

describe 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:

JavaScript
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));
Output
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:

JavaScript
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);
Output
Hi, I am Asha
true

You will see this style in older code and libraries.

Classes use prototypes too#

A class is a cleaner syntax for the same mechanism:

JavaScript
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"));
Output
function
false
true

Methods 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
JavaScript
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"));
Output
Bike has 2 wheels
Car has 4 wheels
false

Key takeaway#

Finished this lesson?