I've read a ton of materials about prototypes and understand inheritance in general. However, this is one thing that is bugging me and I cannot figure it out.
On dmitrysoshnikov.com there is a simplified example of how prototypal inheritance could be achieved with the following snippet:
// Generic prototype for all letters.
let letter = {
getNumber() {
return this.number;
}
};
let a = {number: 1, __proto__: letter};
let b = {number: 2, __proto__: letter};
// ...
let z = {number: 26, __proto__: letter};
console.log(
a.getNumber(), // 1
b.getNumber(), // 2
z.getNumber(), // 26
);
Which follows with this diagram
However, when we start to use the actual inheritance constructions (with the new keyword) it starts to look like this:
I understand how it works. What I don't understand is why suddenly we need the Letter.prototype object from which all the child instances inherit from instead of having it like the first diagram above. To me, it didn't seem like anything was broken with the first example.
One potential reason I can think of is that the actual way allows implementing static methods/properties in classes. In the example above if you'd add a static method then it would be a function added to the Letter object but not Letter.prototype object. The child objects (a,b,z) would have no access to that function. In the first example, this kind of feature would have to be implemented differently but I still don't think that's a good enough reason to create the new Prototype object. I think this static methods feature could be implemented without it.
Am I missing something?
EDIT:
I think there is a lot of people trying to explain things which I'm grateful but I'm not sure my question of WHY was javascript runtime designed to behave one way instead of another properly understood.
To show what I mean here is a few things I tried.
class Car{
method() {
console.log("hello")
}
}
myCar = new Car();
// First a few tests as expected
myCar.method() // works
console.log(myCar.method === Car.method) // False, JS doesn't work that way, ok...
console.log(myCar.method === Car.prototype.method) // This is how it works, fine...
// How about we move the reference to the method up one level
Car.method = Car.prototype.method
// Delete the reference to it in prototype object,
// Btw. I tried to remove reference to whole prototype but somehow doesn't let me
delete Car.prototype.method
// Change the prototype chain so it links directly to Car and not Car's prototype object
myCar.__proto__ = Car
myCar.method() // Still works!!!
console.log(myCar.method === Car.method) // True !
console.log(myCar.method === Car.prototype.method) // False, we deleted the method property out of Car.prototype
So, Car.prototype is not needed anymore, at least not for myCar's execution.
So why does the method go inside Car.prototype and not Car
and then why not myCar.__proto__ = Car instead of myCar.__proto__ = Car.prototype?


It's not (objectively) and certain people (like Douglas Crockford) have often advocated to avoid
.prototypeandthisall together and useObject.create(similar to your__proto__example).So why do people prefer to use classes, inheritance and .prototype?
Prototypes are all about reuse
The reason you typically prototypes is to reuse functionality (like
getNumberabove). In order to do that it's convenient to use a constructor.A constructor is just a function that creates objects. In "old" JavaScript you would do:
ES2015 made this even easier:
So to sum it up: you don't have to use .prototype and classes, people do so because it is useful. Note the prototype chain is as large in both examples.