JavaScript [[Prototype]] vs .prototype

Nirab Pant
5 min readOct 15, 2021

--

Overview of the ‘Function’ and ‘Object’ constructor functions and their prototype objects (‘prototype’ property) and how they cross-reference each other via their respective ‘[[Prototype]]’ properties. Also shown are a function literal ‘func’ which inherits from ‘Function.prototype’ and an object literal ‘obj’ that inherits from ‘Object.prototype’.

Learning object-oriented programming (OOP) in JavaScript can be challenging because, well, learning OOP is intrinsically challenging.

Adding to this inherent complexity, however, is that the terminology used can be rather confusing as well. For example, take the following statement regarding the above diagram: “The prototype of the Function constructor is the very same object as that of its prototype property, which itself has as its prototype the null prototype object, Object.prototype.”

If you’re not a very active user of JavaScript then I would find it remarkable if this statement is at all comprehensible to you. Even then, having to tread extra carefully to ensure we’re using the right terminology when discussing our code with the team just adds another source of friction, slowing down development.

This article aims to clarify some of the common sources of confusion around OOP in JavaScript and elaborate on the schematic shown above. The goal is that the schematic should serve as a nice summary of all concepts discussed here, and that a brief glance should suffice to refresh your memory.

Functions are Objects

When starting out with OOP in JS, the first point that should be appreciated is that all functions are objects. The schematic shows two constructor functions, Function and Object, which are themselves objects. Thus, as with all objects, these function objects have certain properties and methods (behaviors).

Here, the two function objects are shown with two properties, [[Prototype]] and prototype. This brings us to the first major source of confusion, the difference between the two.

[[Prototype]] vs prototype

[[Prototype]] is a hidden property of all objects in JS and are accessible using the static method Object.getPrototypeOf(). It is also accessible using the __proto__ property, however, this is a deprecated feature and not recommended for use in production code.

[[Prototype]] is what we typically mean when refer to the ‘prototype’ of a given object, namely, what parent object does it inherit its properties and methods from.

In the above diagram, both the Function constructor and the Object constructors inherit from [[Prototype]] of the Function constructor (remember all functions, including constructor functions, are objects in JS). We can test this as follows:

Both Function and Object constructors have a prototype that is a function object.

Thus, we see that the prototype ([[Prototype]]) of both the Function and Object constructors is a function object accessible using Object.getPrototypeOf(Function). Alternatively, this function object is accessible using any of Object.getPrototypeOf(Object), Object.__proto__, Function.__proto__, although the last two are not recommended for production code.

On the other hand, the prototype property in the Function and Object constructor objects sets the prototype of the instance returned by the function when it is invoked using the new keyword.

It is important to note that the prototype property only exists by default in function objects. This means that any function can be used as a constructor using the new keyword, and it will create a new object with its prototype set using the methods and properties defined on the function’s prototype property.

Furthermore, the prototype property of the Function constructor is the very same object that serves as a prototype of the constructor itself. This is shown in the code below where Function.prototype === Object.getPrototypeOf(Function) returns true.

Testing that the constructor property of both the Function and Object constructor functions is the Function constructor, i.e., Function is a constructor for itself. Furthermore, its [[Prototype]] is the same as the prototype of object instances it creates (accessible using the prototype property key).

Another point to note here is that every object will have a constructor property which points to the constructor function that created it (regardless if it was created explicitly or not). The code above shows that both the Function and Object constructors have the same constructor, namely, the Function constructor ( Function is an instance of itself).

Finally, we can follow the prototype chain of Function.prototype to see that its prototype is Object.prototype which is the base object prototype as it does not inherit from any other objects. We can test this using Object.getPrototypeOf(Object.prototype) which returns null.

Prototypes and Constructors of Object Literals and Function Literals

Schematic showing a function literal and an object literal created using, respectively, the ‘Function’ and ‘Object’ constructors. Note that only the function literal has a ‘prototype’ property that references its prototype object that can be used to set the ‘[[Prototype]]’ of any new objects created using the ‘new’ keyword. This prototype object also holds a ‘constructor’ property that indicates the type of any new objects created using this function literal.

Finally, to further cement and validate our understanding, let’s take a look at the two new objects created above, where one is a function literal (remember, functions are objects) and the second an object literal.

Note that only the function object has the prototype property, i.e., the object that will be used as a template if we decided to use this function as a constructor using the new keyword. Furthermore, this default prototypical object in turn inherits from the base (or null) prototype object, Object.prototype.

Other aspects of the diagram should not be too surprising. For example, the object literal and function literal have as their prototypes, respectively, Object.prototype and Function.prototype. Again, this is to be expected because these are what the respective constructors use as a template when they create new object instances.

Conclusion

In summary, the main source of confusion in OOP in JS appears to stem from the distinction between [[Prototype]] and prototype, and not being disciplined in our usage of the two terms. In particular, the former is what is conventionally referred to when we ask for the prototype of a given object. On the other hand, the latter is a property of function objects, and only those. It is used when when invoke the function using the new keyword which creates a new object instance using the object defined on the prototype property as a template.

Finally, returning back to the initial, somewhat obscure statement: “The prototype of the Function constructor is the very same object as that of its prototype property, which itself has as its prototype the null prototype object, Object.prototype.”

Hopefully this statement has now been rendered a little more comprehensible. The first part of the statement asserts that the prototype of the Function constructor is the same object referenced by its prototype property, i.e. Function.__proto__ === Function.prototype.

The second part of the statement simply asserts that Function.prototype inherits from Object.prototype, also known as the null prototype as it is the base object that doesn’t inherit from any other objects.

--

--