What is really the 'prototype' property?

Hello people, I hope you’re all doing right. I’m a bit confused about the concept of prototypal inheritance. I understand that each object has a public, non enumerable property called prototype, and that this property is either an object or null.
So, when I use the new keyword, the object inside the prototype property of the constructor will be linked to the new object as its [[Prototype]]. For instance:

let object = {title: 'FreeCodeCamp', status: 'super happy'};
function Build(){} //shallow function
let newObject = new Build; /*//look into Build's prototype property and link it to the new object as its *[[Prototype]]*. 
(I understand the *prototype* property is triggered only 
when we call a function with the *new* keyword, 
and also that we literally mean a regular property called 'prototype')*/

//At this point, the *prototype* of Build it's just 
//an object with just one property, *constructor*, that points to //the function itself

Build.prototype.constructor //[Function: Build]  

//Of course, I can change it: 

let testObject = {
coolProperty: "I'm cool",
available: true
}
Build.prototype = testObject;
Build.prototype // { coolProperty: 'I\'m cool', available: true } is now the object stored inside the 'prototype' property of Build
 
let x = new Build; //it's the same as saying: link x to { coolProperty: 'I\'m cool', available: true }

We know that, in prototypal inheritance (one of the coolest things about JS), if a property is missing from an object the [[Prototype]] chain will be looked up. In the case above, x does not have a ‘coolProperty’ ; but the engine looks up at the prototypal chain and finds ‘coolProperty’ in testObject. Great, we’ve got. So where is my confusion? It’s probably because I confuse the literal prototype (that is, a regular property that exist inside an object) and [[Prototype]] (probably because of that ‘link the object present into prototype to the newly crated object as its [[Prototype]]’. For instance:

//literal object
let x = {};

//function
function func(){}

Object.getOwnPropertyDescriptor(func, 'prototype'), //the functions does have a prototype property
Object.getOwnPropertyDescriptor(x, 'prototype') //undefined

So all objects have a prototype that is either another object or null. Why then can I access the one inside func but not inside x? Both are instances of Object; both [[Prototype]] chains end with it, then null… What is really this prototype property? To me it seems a key that stores just the next level of the prototypal chain. Because, if the chain was literally stored inside of it, and If we had to use it to reach to the [[Prototypal]] for properties we don’t have in our object, a simple snippet like this one would cancel the whole chain:

let x = {}; //empty object
x.prototype = null; //set the prototype to null
x.hasOwnProperty(); //I can still borrow methods from the Object ancestor

//here we really cut off an object from the prototypal chain
let y = Object.create(null);
y.toString() //TypeError: y.toString is not a function (we cannot get it from Object)


I can clearly see that the prototype property has nothing to do with the [[Prototype]], which is hidden. So is it just a key that stores the next level of the chain? (that stores another level and so on till the Object). I’m sorry for this super long post, but I’m still quite confused about it…

You’re correct that these are two completely different things:

  • the prototype property (can be accessed via myObj.prototype )
  • the __proto__ property (can be accessed via Object.getPrototypeOf(myObj)

The first is a property that is present on functions. If you use your function as a constructor function and create a new object with the new keyword, then the newly created object’s __proto__ property will point at the object that the constructor function’s prototype property points at. Pardon this monster of a sentence.

The second gives you access to the prototype chain. This:
myObject.__proto__.__proto__
will at some point reach the Object prototype, then null at the end of the chain.

Here’s a video that explains it really well:

This is actually a nice and clear sentence. Trust me, the documentation can be far more confusing. I’m reading You don’t know Js, this & Object Prototypes by Kyle Simpson, and he writes very clearly about the issue of using that damn prototype term. To thank you for your time, I’ll post a quote from the book:

function Foo() {
 // ...
}
Foo.prototype; // { }

This object is often called Foo’s prototype, because we access it via an unfortunately named Foo.prototype property reference. However, that terminology is hopelessly destined to lead us into confusion, as we’ll see shortly. Instead, I will call it “the object formerly known as Foo’s prototype.” Just kidding. How about “the object arbitrarily labeled Foo dot prototype”?

I have yet to read that book, sounds like it’s worth the time. That video I linked made it click for me though, learning that .prototype is only present on functions (and why).