Interfaces in JavaScript

// Here's a basic interface for geometric shapes.
class Geometry {
    area() {
        throw new Error("Method 'area()' must be implemented.");
    }
    perim() {
        throw new Error("Method 'perim()' must be implemented.");
    }
}

// For our example we'll implement this interface on
// `Rect` and `Circle` classes.
class Rect extends Geometry {
    constructor(width, height) {
        super();
        this.width = width;
        this.height = height;
    }

    area() {
        return this.width * this.height;
    }

    perim() {
        return 2 * this.width + 2 * this.height;
    }
}

class Circle extends Geometry {
    constructor(radius) {
        super();
        this.radius = radius;
    }

    area() {
        return Math.PI * this.radius * this.radius;
    }

    perim() {
        return 2 * Math.PI * this.radius;
    }
}

// If a variable has an interface type, then we can call
// methods that are in the named interface. Here's a
// generic `measure` function taking advantage of this
// to work on any `Geometry`.
function measure(g) {
    console.log(g);
    console.log(g.area());
    console.log(g.perim());
}

function main() {
    const r = new Rect(3, 4);
    const c = new Circle(5);

    // The `Circle` and `Rect` classes both
    // implement the `Geometry` interface so we can use
    // instances of these classes as arguments to `measure`.
    measure(r);
    measure(c);
}

main();

In JavaScript, we don’t have a built-in interface concept like in some other languages. However, we can simulate interfaces using classes and inheritance. In this example, we define a base Geometry class that acts as our interface.

The Rect and Circle classes extend the Geometry class and implement the area() and perim() methods. This is equivalent to implementing an interface in languages with explicit interface support.

The measure function demonstrates polymorphism by accepting any object that adheres to the Geometry interface (i.e., has area() and perim() methods).

In the main function, we create instances of Rect and Circle and pass them to the measure function, showing how we can use these objects interchangeably where a Geometry is expected.

To run this program, you would save it to a file (e.g., geometry.js) and execute it with Node.js:

$ node geometry.js
Rect { width: 3, height: 4 }
12
14
Circle { radius: 5 }
78.53981633974483
31.41592653589793

This example demonstrates how to implement interface-like behavior in JavaScript using classes and inheritance, providing a similar structure to the original example while using JavaScript’s object-oriented features.