TL;DR: [[Prototype]] is an internal property that exists on all JS objects. It can be accessed via the __proto__ property. .prototype is an object which exists only on function constructors and is used to set a constructed object's internal [[Prototype]]

If you have ever been confused about all the different kinds of prototypes in JavaScript, you are not alone. This article is an overview and explanation of the different kinds of prototypes and their purposes in JavaScript.

[[Prototype]]

In the ECMAScript specifications double brackets denote internal properties and are, according to the specs, not part of the ECMAScript language. This means that those internal properties are not accessible by the objects that contain them.

[[Prototype]] is an internal property on all JS objects that points to the object's prototype. Every JS object has an internal [[Prototype]] . This goes for for objects created with object literals, those created with the new keyword and also for those created with Object.create() . Further, even function constructors have an internal [[Prototype]] .

__proto__

Since [[Prototype]] is an internal property it was never meant to be accessible by developers, according to the ECMA specs. At some point, however, browser vendors and other environments started giving access to the internal [[Prototype]] object via the __proto__ property.

This means that __proto__ and [[Prototype]] refer to the same thing.

__proto__ is simply a way to access the internal [[Prototype]] in some JS environments.

The internal [[Prototype]] is a regular JS object and thus also has an internal [[Prototype]] and so on. This goes all the way down to Object .prototype . The internal [[Prototype]] of Object .prototype is null. This is called the prototype chain. More on that later.

.prototype

The .prototype property only exists on function constructors! When you define a function, the constructor is given an almost empty .prototype object for free. The only property on this object is .constructor , which points back to the function constructor, i.e. .prototype has a property .constructor and vice versa.

When you create a new object with the new keyword, its internal [[Prototype]] is set to the .prototype of the function constructor that was used to create the object.

Object creation prototype chain

Let's look at how the internal [[Prototype]] object is set when creating an object with the new keyword, as an object literal and with Object.create() .

new keyword

When you create a new object with the new keyword, that object's internal [[Prototype]] is set to the constructor function's .prototype

function Car(){} const mCar = new Car(); mCar.__proto__ === Car.prototype; // true

Object literal

When you create a new object with the object literal syntax the object's internal [[Prototype]] is set to Object .prototype .

const obj = {}; obj.__proto__ === Object.prototype; // true

Object Create

When you create a new object with Object.create() , the internal [[Protoype]] of the created object is set to the object passed in as the first argument to Object.create() .

const car = { wheels: 4 }; const mCar = Object.create(car); mCar.__proto__ === car // true

Prototype chain

Since the internal [[Prototype]] object is simply that, an object, it too has an internal [[Prototype]] , which in turn, yada yada yada.

This leads to a prototype chain.

If a prototype is not specified for an object explicitly, then the default value for __proto__ is taken: Object.prototype .

Object.prototype itself also has a __proto__ , which is the final link of the chain and is set null .

If a property or method isn't found on an object instance, the prototype chain is traversed. The first found property/method with the same name is used. If none is found in the entire chain, all the way down to Object.prototype, undefined is returned.

Properties in the prototype chain are called 'inherited properties' as opposed to properties on the instances themselves which are 'own properties'.