Back to JavaScript
2026-02-245 min read

JavaScript Prototypes

Learn JavaScript Prototypes step by step with clear examples and exercises.

Why This Matters

In this comprehensive lesson, we will delve into the world of JavaScript prototypes - a fundamental concept that underpins object-oriented programming (OOP) in JavaScript. Understanding prototypes is crucial for acing interviews, debugging real-world issues, and writing efficient code. Let's embark on our journey!

Prerequisites

Before diving into the core concept of JavaScript prototypes, it's essential to have a solid grasp of the following topics:

  1. Basic JavaScript syntax and data types
  2. Functions in JavaScript
  3. Objects in JavaScript
  4. Understanding ES6 class syntax (optional but recommended)
  5. Familiarity with the concept of inheritance in object-oriented programming

Core Concept

What are Prototypes?

In JavaScript, every object has an internal property called [[Prototype]], which is a reference to another object. This other object serves as the prototype for the given object and provides default properties and methods that can be inherited. The prototype chain allows objects to inherit properties and methods from their prototypes, all the way up to the top of the chain, which is the Object constructor.

Creating and Accessing Prototypes

You can create a new object with a specified prototype by using the Object.create() method or by assigning the prototype directly:

let vehicle = {
// properties and methods go here
};

let car = Object.create(vehicle); // Using Object.create()
car.__proto__ = vehicle; // Assigning prototype directly

Inheritance and Method Overriding

When you access a property or method on an object that doesn't have it, JavaScript searches the prototype chain for the property or method. If it finds one, it returns that; otherwise, it returns undefined. This allows objects to inherit properties and methods from their prototypes.

You can also override properties and methods in child objects by defining them again:

let vehicle = {
startEngine() {
console.log('Engine started');
}
};

let car = Object.create(vehicle);
Object.defineProperty(car, 'startEngine', {
value: function() {
console.log(`Starting engine of ${this.make}`);
}
});

Now, when you call car.startEngine(), it will execute the method defined in the car object, and not the one inherited from the vehicle prototype.

Prototype Chains

The prototype chain is a series of objects that an object inherits properties and methods from. Each object's prototype is another object, which may have its own prototype, and so on, until we reach the top of the chain - the Object constructor. When you access a property or method on an object, JavaScript looks for it in the object itself, then moves up the prototype chain until it finds the property or method or reaches the end of the chain.

The Role of Constructors in Prototypes

In JavaScript, constructors are special functions that create new objects and set their prototypes to the constructor's prototype property. This allows multiple instances of an object to share the same prototype and its properties and methods:

function Vehicle(make, model) {
this.make = make;
this.model = model;
}

Vehicle.prototype.startEngine = function() {
console.log('Starting engine...');
};

let car = new Vehicle('Toyota', 'Corolla');

In this example, car is an instance of the Vehicle constructor and inherits properties and methods from its prototype (Vehicle.prototype).

Worked Example

Let's create a simple example of inheritance using prototypes:

function Vehicle(make, model) {
this.make = make;
this.model = model;
}

Vehicle.prototype.startEngine = function() {
console.log('Starting engine...');
};

let carPrototype = Object.create(Vehicle.prototype);
carPrototype.drive = function() {
this.startEngine();
console.log('Driving...');
};

let toyotaCorolla = Object.create(carPrototype);
toyotaCorolla.make = 'Toyota';
toyotaCorolla.model = 'Corolla';
toyotaCorolla.drive(); // Starts, drives, and stops the engine of a Toyota Corolla

Common Mistakes

  1. Forgetting to set the prototype: If you don't explicitly set an object's prototype, it will inherit from Object.prototype. This can lead to unexpected behavior when accessing or defining properties and methods.
  2. Overriding essential methods: Be careful when overriding methods like toString() or hasOwnProperty(), as they have specific behaviors in JavaScript that may be relied upon by other parts of your code or built-in functions.
  3. Misunderstanding prototype chains: It's important to understand how the prototype chain works and how it affects property and method lookup. A common mistake is assuming that properties and methods are always inherited from the immediate prototype, rather than searching the entire chain.
  4. Not using constructors properly: Constructors should be used to create new objects with a specific prototype and shared properties and methods. Failing to use constructors can lead to redundant code and inconsistent object structures.
  5. Confusing __proto__ with constructor's prototype: While you can access an object's prototype using the __proto__ property, it's important to remember that this is not the same as a constructor's prototype property. The former refers to an individual object's prototype, while the latter is used when creating new objects with a constructor.

Practice Questions

  1. Create a Person constructor with properties for name, age, and occupation. Then create an instance of Student, which inherits from Person and has a property for school.
  2. Write a function that takes an object and returns the length of its prototype chain (i.e., the number of prototypes between the given object and Object.prototype).
  3. Given the following objects, determine the output of each expression:
let vehicle = {
startEngine() {
console.log('Starting engine...');
}
};

let car = Object.create(vehicle);
car.make = 'Toyota';
car.model = 'Corolla';

let toyotaCorolla = Object.create(car);
toyotaCorolla.drive = function() {
this.startEngine();
console.log('Driving...');
};

console.log(toyotaCorolla.make); // Output: 'Toyota'
console.log(toyotaCorolla.hasOwnProperty('make')); // Output: true
console.log(vehicle.isPrototypeOf(toyotaCorolla)); // Output: true
  1. Implement a simple inheritance hierarchy for animals, where Mammal has properties name and species, and Cat inherits from Mammal. Create instances of both Mammal and Cat, and demonstrate the use of prototypes to share common properties and methods.
  2. Write a function that creates a new object with a specified prototype and properties, using either Object.create() or by assigning the prototype directly.

FAQ

  1. Why don't we use classes in JavaScript for inheritance?
  • While ES6 introduced classes, they are syntactic sugar that compile to prototype-based code. Under the hood, classes still rely on prototypes and the prototype chain.
  1. What happens when you call a method on an object that doesn't exist in its prototype chain?
  • If you call a method on an object that doesn't exist in its prototype chain, JavaScript will return undefined.
  1. Can I change an object's prototype after it has been created?
  • Yes, you can change an object's prototype at any time by setting the __proto__ property or using Object.setPrototypeOf(). However, changing an object's prototype doesn't affect objects that have already been created with that object as their prototype.
  1. What is the difference between __proto__ and constructor's prototype?
  • The __proto__ property refers to an individual object's prototype, while the constructor's prototype property is used when creating new objects with a constructor.
  1. Why should I use constructors in JavaScript?
  • Constructors help create new objects with a specific prototype and shared properties and methods. They also ensure that all instances of an object are created consistently.
JavaScript Prototypes | JavaScript | XQA Learn