Appearance
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()); // 400Prototype 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.prototypeThis forms a lookup chain:
square → Square.prototype → Object.prototypeThis 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
classsyntax, which we'll see next, provides a much clearer way to express these relationships.
External Resources