Skip to content

Prototypes

Unlike languages like C++ or Python, JavaScript doesn't have traditional class-based inheritance. Instead, objects can be linked to other objects through a prototype chain. While modern JavaScript provides a cleaner class syntax (which we'll see next), understanding prototypes helps explain how JavaScript objects work.

From Object Literals to Constructors

We've seen how to create a single object with properties and methods:

js
const shape = {
    colour: "red",
    getColour() {
        return this.colour;
    }
};

But what if we need many similar shapes with different colours? Instead of copying and pasting, JavaScript traditionally used constructor functions:

js
// A function that creates shape objects
function Shape(colour) {
    this.colour = colour;
}
Shape.prototype.getColour = function() {
    return this.colour;
};

// Create multiple shapes
const shape1 = new Shape("red");
const shape2 = new Shape("blue");

Constructor Functions

The new keyword is special: it creates an object and links it to the function's prototype. Functions used this way are called constructor functions and, by convention, start with a capital letter:

js
function Square(colour, size) {
    // When called with 'new':
    // - 'this' is a new empty object
    // - the object is linked to Square.prototype
    this.colour = colour;
    this.size = size;
}

// Methods added to prototype are shared by all squares
Square.prototype.getArea = function() {
    return this.size * this.size;
};

const square1 = new Square("red", 10);
const square2 = new Square("blue", 20);

// Each square has its own properties
console.log(square1.colour);  // "red"
console.log(square2.colour);  // "blue"

// But they share the same method
console.log(square1.getArea());  // 100
console.log(square2.getArea());  // 400

Prototype Chain

When you access a property or method on an object, JavaScript looks for it in a sequence of linked objects:

js
const square = new Square("red", 10);

// Looking up a property or method checks each level:
console.log(square.size);      // Found directly on square object
console.log(square.getArea);   // Not found on square, found in Square.prototype
console.log(square.toString);  // Not found in either, found in Object.prototype

This forms a lookup chain:

square → Square.prototype → Object.prototype

This is similar to how C++ looks for methods in a class hierarchy, but with a key difference:

  • In C++: Child class inherits methods from parent class at compile time
  • In JavaScript: Objects link to other objects at runtime, forming a lookup chain

Building an Inheritance Hierarchy

Here's how you might create a hierarchy of shapes using constructor functions:

js
function Shape(colour) {
    this.colour = colour;
}
Shape.prototype.draw = function() {
    return `A ${this.colour} shape.`;
};

function Square(colour, size) {
    // Call the parent constructor with this object's context
    Shape.call(this, colour);
    this.size = size;
}
Square.prototype.draw = function() {
    return `A ${this.colour} square with size ${this.size}`;
};

function Circle(colour, radius) {
    Shape.call(this, colour);
    this.radius = radius;
}
Circle.prototype.draw = function() {
    return `A ${this.colour} circle with radius ${this.radius}`;
};

// Create different types of shapes
const square = new Square("red", 10);
const circle = new Circle("blue", 5);

console.log(square.draw());  // "A red square with size 10"
console.log(circle.draw());  // "A blue circle with radius 5"

💡 This pattern of constructor functions calling parent constructors was the traditional way to create inheritance hierarchies in JavaScript. The class syntax, which we'll see next, provides a much clearer way to express these relationships.