Prototypal Inheritance

You probably know how OOP works. The class Dog inherits from class Animal, which means that if you have a Dog you access methods from Animal. This is actually just a subset of OOP. You can be object oriented without classes, and that's what JavaScript does.

A class is a blueprint. It contains information about what every instance of that class has. It tells you which methods and properties are there and how you can use this class of things.

The class itself doesn't actually contain any data. That's the job of an object. A class is the blueprint for a house, but an object is the actual house, with wood, tiles, bricks and all the weight of an actual house. An instance contains the actual data that is individual only to that instance. You might have used the same blueprint for your house as your neighbor, but that doesn't mean you can sleep in their bed.

The difference between instances and classes is fundamental in the way most people understand OOP. But it's not necessary for OOP. There's a way to do OOP without classes. After all, it's object oriented programming: objects are the star of the show, not classes.

The style of OOP where there is no difference between classes and objects is called prototype-based programming (to make our lives easier, we'll call it PBP).

In PBP, every object can be individual. It contains both its methods and data at the same time. Usually, you can add new properties and methods to an object whenever you feel like it, even while the program is running.

If this sounds like something only a few programmers use for their edge case problems, you'd be surprised. One of the most popular languages in the world is a PBP language: JavaScript.

In JavaScript, there are no classes in the class-based OOP sense of the word. JavaScript works with objects. If you want to encapsulate a few functions and properties together, you would create an object containing functions and properties, and not a class.

const animal = {
    numberOfLegs: 4,
    sleep: () => print("Zzz")
}

This is an object that has a property and a function that does some work. This is different from a class because the function itself is a piece of data that the object has. It's as mutable as the state of a property.

animal.sleep = null

Now, suddenly, animal doesn't have a function anymore. JavaScript doesn't have blueprints, it only has houses.

What About Inheritance, Though?

A fundamental property of a class is that it can inherit methods and properties from other classes. Both a House and Apartment can inherit from Residence to make sure we don't have to duplicate the same code in both classes.

But again, classes are not necessary for inheritance. In PBP inheritance is done completely by using objects.

I mentioned earlier that in PBP an object contains all of its methods and properties, as well as their actual state. So the only way to inherit all of those is by copying (or referencing) all those methods and properties. This is exactly what PBP languages do, and it's called prototypal inheritance.

If we wanted to make a dog object which would have access to the same methods as animal, we can simply make dog contain animal, since the methods are inside of animal.

const dog = {
    prototype: animal,
    bark: () => print("Woof!")
}

If we want to make the dog eat food, we can to this:

dog.prototype.eatFood(10)

Thankfully, JavaScript calls functions on the prototype automatically. If a function doesn't exist on that object, it will search the prototype for the function. The prototype can itself contain another prototype, so JS will search all the way up until it finds the function it's looking for.

The reason why they're called prototype based languages is because a prototype is, as opposed to a class, concrete. A prototype is a working thing, and not a blueprint. You might not want to sell the prototype to millions of customers, but it's a real thing that works. You then use that prototype to construct a bunch of copies that you will actually use. Just like you would in a factory.

The animal object is a prototype of an animal. It's an object like any other, but it will be used to create new, concrete animals, like a dog.

Is This Better Than Classes?

PBP is more straightforward than class-based OOP. It has fewer moving parts and is completely transparent. You can see how it works. Class-based OOP is a layer of abstraction on top of this. This means PBP has a lot of advantages, but also disadvantages.

The main advantage of PBP lies in its flexibility. Blueprints are something that has to be made ahead of time, and they have to be correct. If you're building a house, you will have a lot of trouble if you realize half-way trough building your roof that you forgot to add a window in the blueprint. Classes are similar: you create them before creating and using the objects. You have to know which methods and properties you'll need before you start using it. No matter how good you are at programming, you won't be able to predict everything.

If you don't have to make a class ahead of time, you can immediately start creating your objects. You can adapt them as you're using them without having to pay a large cost. This is very beneficial in programming, where requirements change all the time. You want the ability to change quickly and easily.

But quick and easy change comes with a big risk: correctness. Blueprints exist to plan out a house before it's built, so mistakes are caught early and workers don't get lost while building. If you try to build a house by just doing it and seeing where it leads you, you will probably end up with the house collapsing on top of you. The same goes for programming: you need to make sure your codebase is sound and correct. If everyone can just go in and start changing everything, it will quickly collapse on top of itself.

Like everything in programming, PBP and class-based OOP fall in a spectrum of tradeoffs. On one hand, PBP is flexible and easy to work with, leading to quicker development. On the other hand, class-based OOP is more rigid and sturdy, leading to fewer bugs. Different problems require different tools, and with the knowledge of PBP, you are now better equipped to solve problems that require it. Happy coding!

References:

Prototype based programming
https://en.wikipedia.org/wiki/Prototype-based_programming

Inheritance and the prototype chain - JavaScript
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

Lazy Evaluation

Recursion & Tail Call Optimization