With bite-size code snippets and easy explanations. Introduction JavaScript prototypes are confusing and unfamiliar to many developers and engineers. Today, it’s time to demystify and master prototypes once and for all. Doing so will give us the confidence to deal with prototypes when we inevitably encounter and use them in JavaScript. Sections This guide is divided into the following sections. Effects of creating a function Invoking a function as a constructor Demonstration of prototypal inheritance Traversal of the prototype chain Components of the prototype chain A function’s prototype Prototypes without constructors Why is a prototype called a prototype? Tips on how to read this guide Each section builds on the previous one. As such, don’t skip sections, especially if you are reading this guide for the first time. All code snippets are relevant and are cumulative across sections. Code snippets should work well with recent versions of JavaScript. If you scroll through this guide too quickly, you may not gain much from it. Try to read this guide carefully and you will likely become convinced of what prototypes are and how to use them. It’s time to demystify and master prototypes once and for all. Effects of creating a function Creating a function has two effects. The function itself will be created.Note that a function is also an object and thus it can have additional properties. A second object will be created and become attached to the function as <Function>.prototype. To illustrate these effects, create a function named Person and observe that it automatically comes with a Person.prototype object. function Person(name) {this.name = name;} typeof Person.prototype; // "object" Invoking a function as a constructor When we invoke the Person function with the new keyword, i.e. as a constructor, a new object this is implicitly created, this.name is set, and finally, this is implicitly returned. function Person(name) {this.name = name;} const alex = new Person("Alex");typeof alex; // "object"alex.name; // "Alex" Demonstration of prototypal inheritance Importantly, the object alex and any other object constructed from Person will gain indirect access to Person.prototype. Let’s add a greet function to Person.prototype. Notice that the existing object alex can now greet, and a newly created object tom can do the same. This form of code reuse is known as prototypal inheritance. Person.prototype.greet = function() {console.log(`Hi ${this.name}`);} alex.hasOwnProperty("greet"); // falsealex.greet(); // "Hi Alex" const tom = new Person("Tom");tom.greet(); // "Hi Tom" Even though the object alex constructed from Person does not have a greet property on itself, it was able to access Person.prototype and thus invoke Person.prototype.greet with this being implicitly set to alex, which results in “Hi Alex” being logged to the console. The other object tom gains access to the same Person.prototype object in a similar way. Traversal of the prototype chain The traversal algorithm consults the object’s prototype when it cannot find the desired property on the object. If it finds the property on the prototype, the traversal stops. Otherwise, it will consult the prototype of the prototype, and so on, until it finds the property or it reaches the end of the prototype chain. At each traversal, the object delegates the responsibility of doing something to its prototype if it does not know how to do it. alex did not know how to greet, so alex asked Person.prototype for help on how to greet. Components of the prototype chain Let’s use Object.getPrototypeOf to check alex’s entire prototype chain. Object.getPrototypeOf(alex) === Person.prototype; // true The line above tells us that the prototype of alex is Person.prototype. Therefore, if JavaScript cannot find the desired property on alex, it will check Person.prototpe. In other words, alex’s prototype chain starts with Person.prototype. If JavaScript is still unable to find the desired property on Person.prototype, it will look at the prototype of Person.prototype, which is Object.prototype. Object.getPrototypeOf(Person.prototype) === Object.prototype; // true Why is Object.prototype the prototype of Person.prototype? Suppose that Person.prototype, which is an object, was constructed from the built-in Object constructor (whether or not this is the case is an implementation detail). You can observe a pattern consistent with what we have learned so far. alex was constructed from Person.The prototype of alex is Person.prototype. Person.prototype was constructed from Object.The prototype of Person.prototype is Object.prototype. You can go from statement 1 to 2 by first substituting Person with Object, and then substituting alex with Person.prototype. To recap, we have seen that the prototype of alex is Person.prototype, and the prototype of Person.prototype is Object.prototype. Therefore, alex’s prototype chain contains Person.prototype followed by Object.prototype. Is Object.prototype the final prototype in alex’s prototype chain? Yes, because Object.prototype does not have a prototype (it is null). Object.getPrototypeOf(Object.prototype) === null; // true Even though Object.prototype is an object, its prototype is not Object.prototype, otherwise we will have an infinite prototype chain. Nearly all other objects in JavaScript have Object.prototype at the end of their prototype chains. We have seen how it is so for the object alex which was constructed from Person. This property also applies to plain objects created from the built-in Object constructor and the object literal syntax. const constructedObject = new Object();const objectLiteral = {}; Object.getPrototypeOf(constructedObject) === Object.prototype; // trueObject.getPrototypeOf(objectLiteral) === Object.prototype; // true The fact that nearly all objects have Object.prototype at the end of their prototype chains is of practical significance because they will have access to common utilities offered by Object.prototype such as toString and valueOf. alex.toString(); // "[object Object]"alex.valueOf(); // Person { name: "Alex" } A function’s prototype Earlier, we saw that alex has a name property which can be accessed using alex.name. The syntax does not say anything more about alex, but we usually add more meaning to it. We think that alex.name is not just any random name that happens to be accessible at alex.name, but instead refers to Alex’s name. What about Person.prototype? Does it refer to Person’s prototype? Nope! Object.getPrototypeOf(Person) !== Person.prototype; // true If Person.prototype does not refer to Person’s prototype, then whose prototype does it refer to? Well, Person.prototype will become the prototype of objects constructed from Person. We have already seen this behavior with alex. It may help to think of Person.prototype as a gift that Santa deposited at your house, but that gift is meant for your kids and is not yours. So what is the actual prototype of Person? It is Function.prototype. Object.getPrototypeOf(Person) === Function.prototype; // true This is because Person is a Function and thus it has a prototype of Function.prototype. Function.prototype offers common utilities like call, bind and apply which can be accessed from Person and other functions. Prototypes without constructors We can also create prototype chains without constructors. const greeter = {greet() {console.log(`Hi ${this.name}`);}}; const bob = Object.create(greeter);bob.name = "Bob";bob.greet(); // "Hi Bob" Object.getPrototypeOf(bob) === greeter; // true In the above example, Object.create created a new object with greeter as its prototype. That object was then assigned to bob. Although bob does not have its own greet function, it is able to access the greet function on its prototype greeter. Creating a new object with a defined prototype using Object.create is more straightforward than having to deal with a constructor function and the <Constructor>.prototype object. The use of Object.create can be combined with factory functions. Unlike constructor functions, factory functions explicitly return an object and are not invoked with new. Here is an example. function createPerson(name, prototype) {const person = Object.create(prototype);person.name = name;return person;} const ada = createPerson("Ada", greeter);ada.greet(); // "Hi Ada" Given their simplicity and conciseness, the use of factory functions and Object.create tends to be the preferred approach over the use of constructor functions and the <Constructor>.prototype objects. Why is a prototype called a prototype? “Because someone came up with it” is not a satisfactory answer. The word prototype is often glossed over in JavaScript literature. Most people treat it as a technical term and do not explain why it is suitably named “prototype”. Knowing why a prototype is called a prototype can give us a better mental model to work with whenever we encounter it. That being said, it is hard to find an exact answer to this question. Here is my take on this question. A prototype in real life mainly refers to A product, albeit with limited features, where the final version of a product will share some characteristics of its prototype. After substituting the word “product” with “object”, we see that a JavaScript prototype refers to An object, albeit with limited features, where the final version of an object will share some characteristics of its prototype. Point 1 highlights a distinct point about prototypal inheritance as compared to traditional class-based inheritance. The prototype is an object that can be used on its own. However, a traditional class is not an object and thus cannot be used like an object. Note that although later versions of JavaScript have a class keyword, it still uses prototypal inheritance under the hood. Point 2 is valid because a prototype typically has fewer properties compared to an object that uses it as its prototype. For example, both alex and Person.prototype are able to greet (although alex does it with the help of Person.prototype), but alex has an additional name. As for point 3, a JavaScript object does share some characteristics of its prototype(s) because of prototypal inheritance. Since objects are linked in the prototype chain, if you change a prototype, the behavior of existing and future objects linked to that prototype could be affected. As such, be careful not to change a built-in prototype unless you are trying to polyfill a standard feature. If everyone took the liberty of changing built-in prototypes arbitrarily, there will be conflicts and broken code. Summary You have seen what prototypes are, how JavaScript traverses the prototype chain to access prototype properties, and thus how code is reused in what we call prototypal inheritance. You have also seen how to use prototypes, with or without constructor functions. Though the mastery of prototypes has eluded many, I hope that this definitive guide has helped you to master prototypes in JavaScript and thus become a better software developer and engineer. Congratulations for making it all the way here! If you find this guide useful, send it to your colleagues and friends who may benefit from it. For further reading Common Misconceptions About Inheritance in JavaScript by Eric Elliott You Don’t Know JS: this & Object Prototypes by Kyle Simpson With bite-size code snippets and easy explanations. Introduction JavaScript prototypes are confusing and unfamiliar to many developers and engineers. JavaScript Today, it’s time to demystify and master prototypes once and for all. Doing so will give us the confidence to deal with prototypes when we inevitably encounter and use them in JavaScript. Sections This guide is divided into the following sections. Effects of creating a function Invoking a function as a constructor Demonstration of prototypal inheritance Traversal of the prototype chain Components of the prototype chain A function’s prototype Prototypes without constructors Why is a prototype called a prototype? Effects of creating a function Invoking a function as a constructor Demonstration of prototypal inheritance Traversal of the prototype chain Components of the prototype chain A function’s prototype Prototypes without constructors Why is a prototype called a prototype? Tips on how to read this guide Each section builds on the previous one. As such, don’t skip sections, especially if you are reading this guide for the first time. All code snippets are relevant and are cumulative across sections. Code snippets should work well with recent versions of JavaScript. If you scroll through this guide too quickly, you may not gain much from it. Try to read this guide carefully and you will likely become convinced of what prototypes are and how to use them. It’s time to demystify and master prototypes once and for all. Effects of creating a function Creating a function has two effects. The function itself will be created.Note that a function is also an object and thus it can have additional properties. A second object will be created and become attached to the function as <Function>.prototype. The function itself will be created.Note that a function is also an object and thus it can have additional properties. The function itself will be created.Note that a function is also an object and thus it can have additional properties. A second object will be created and become attached to the function as <Function>.prototype . <Function>.prototype To illustrate these effects, create a function named Person and observe that it automatically comes with a Person.prototype object. Person Person.prototype function Person(name) {this.name = name;} typeof Person.prototype; // "object" Invoking a function as a constructor When we invoke the Person function with the new keyword, i.e. as a constructor, a new object this is implicitly created, this.name is set, and finally, this is implicitly returned. Person new this this.name this function Person(name) {this.name = name;} const alex = new Person("Alex");typeof alex; // "object"alex.name; // "Alex" Demonstration of prototypal inheritance Importantly, the object alex and any other object constructed from Person will gain indirect access to Person.prototype . alex Person Person.prototype Let’s add a greet function to Person.prototype . Notice that the existing object alex can now greet , and a newly created object tom can do the same. This form of code reuse is known as prototypal inheritance. greet Person.prototype alex greet tom Person.prototype.greet = function() {console.log(`Hi ${this.name}`);} alex.hasOwnProperty("greet"); // falsealex.greet(); // "Hi Alex" const tom = new Person("Tom");tom.greet(); // "Hi Tom" Even though the object alex constructed from Person does not have a greet property on itself, it was able to access Person.prototype and thus invoke Person.prototype.greet with this being implicitly set to alex , which results in “Hi Alex” being logged to the console. alex Person greet Person.prototype Person.prototype.greet this alex The other object tom gains access to the same Person.prototype object in a similar way. tom same Person.prototype Traversal of the prototype chain The traversal algorithm consults the object’s prototype when it cannot find the desired property on the object. If it finds the property on the prototype, the traversal stops. Otherwise, it will consult the prototype of the prototype, and so on, until it finds the property or it reaches the end of the prototype chain. At each traversal, the object delegates the responsibility of doing something to its prototype if it does not know how to do it. alex did not know how to greet , so alex asked Person.prototype for help on how to greet . delegates alex greet alex Person.prototype greet Components of the prototype chain Let’s use Object.getPrototypeOf to check alex ’s entire prototype chain. Object.getPrototypeOf alex Object.getPrototypeOf(alex) === Person.prototype; // true The line above tells us that the prototype of alex is Person.prototype . Therefore, if JavaScript cannot find the desired property on alex , it will check Person.prototpe . alex Person.prototype alex Person.prototpe In other words, alex ’s prototype chain starts with Person.prototype . alex Person.prototype If JavaScript is still unable to find the desired property on Person.prototype , it will look at the prototype of Person.prototype , which is Object.prototype . Person.prototype Person.prototype Object.prototype Object.getPrototypeOf(Person.prototype) === Object.prototype; // true Why is Object.prototype the prototype of Person.prototype ? Object.prototype Person.prototype Suppose that Person.prototype , which is an object, was constructed from the built-in Object constructor (whether or not this is the case is an implementation detail). Person.prototype Object You can observe a pattern consistent with what we have learned so far. alex was constructed from Person.The prototype of alex is Person.prototype. Person.prototype was constructed from Object.The prototype of Person.prototype is Object.prototype. alex was constructed from Person.The prototype of alex is Person.prototype. alex was constructed from Person .The prototype of alex is Person.prototype . alex Person alex Person.prototype Person.prototype was constructed from Object.The prototype of Person.prototype is Object.prototype. Person.prototype was constructed from Object .The prototype of Person.prototype is Object.prototype . Person.prototype Object Person.prototype Object.prototype You can go from statement 1 to 2 by first substituting Person with Object , and then substituting alex with Person.prototype . Person Object alex Person.prototype To recap, we have seen that the prototype of alex is Person.prototype , and the prototype of Person.prototype is Object.prototype . Therefore, alex ’s prototype chain contains Person.prototype followed by Object.prototype . alex Person.prototype Person.prototype Object.prototype alex Person.prototype Object.prototype Is Object.prototype the final prototype in alex ’s prototype chain? Yes, because Object.prototype does not have a prototype (it is null). Object.prototype alex Object.prototype Object.getPrototypeOf(Object.prototype) === null; // true Even though Object.prototype is an object, its prototype is not Object.prototype , otherwise we will have an infinite prototype chain. Object.prototype Object.prototype Nearly all other objects in JavaScript have Object.prototype at the end of their prototype chains. We have seen how it is so for the object alex which was constructed from Person . This property also applies to plain objects created from the built-in Object constructor and the object literal syntax. Object.prototype alex Person Object const constructedObject = new Object();const objectLiteral = {}; Object.getPrototypeOf(constructedObject) === Object.prototype; // trueObject.getPrototypeOf(objectLiteral) === Object.prototype; // true The fact that nearly all objects have Object.prototype at the end of their prototype chains is of practical significance because they will have access to common utilities offered by Object.prototype such as toString and valueOf . Object.prototype Object.prototype toString valueOf alex.toString(); // "[object Object]"alex.valueOf(); // Person { name: "Alex" } A function’s prototype Earlier, we saw that alex has a name property which can be accessed using alex.name . The syntax does not say anything more about alex , but we usually add more meaning to it. We think that alex.name is not just any random name that happens to be accessible at alex.name , but instead refers to Alex’s name . alex name alex.name alex alex.name alex.name Alex’s name What about Person.prototype ? Does it refer to Person ’s prototype ? Person.prototype Person ’s prototype Nope! Object.getPrototypeOf(Person) !== Person.prototype; // true If Person.prototype does not refer to Person ’s prototype, then whose prototype does it refer to? Person.prototype Person Well, Person.prototype will become the prototype of objects constructed from Person . We have already seen this behavior with alex . Person.prototype Person alex It may help to think of Person.prototype as a gift that Santa deposited at your house, but that gift is meant for your kids and is not yours. Person.prototype So what is the actual prototype of Person ? It is Function.prototype . Person Function.prototype Object.getPrototypeOf(Person) === Function.prototype; // true This is because Person is a Function and thus it has a prototype of Function.prototype . Person Function Function.prototype Function.prototype offers common utilities like call , bind and apply which can be accessed from Person and other functions. Function.prototype call bind apply Person Prototypes without constructors We can also create prototype chains without constructors. const greeter = {greet() {console.log(`Hi ${this.name}`);}}; const bob = Object.create(greeter);bob.name = "Bob";bob.greet(); // "Hi Bob" Object.getPrototypeOf(bob) === greeter; // true In the above example, Object.create created a new object with greeter as its prototype. That object was then assigned to bob . Although bob does not have its own greet function, it is able to access the greet function on its prototype greeter . Object.create greeter bob bob greet greet greeter Creating a new object with a defined prototype using Object.create is more straightforward than having to deal with a constructor function and the <Constructor>.prototype object. Object.create <Constructor>.prototype The use of Object.create can be combined with factory functions. Unlike constructor functions, factory functions explicitly return an object and are not invoked with new . Here is an example. Object.create new function createPerson(name, prototype) {const person = Object.create(prototype);person.name = name;return person;} const ada = createPerson("Ada", greeter);ada.greet(); // "Hi Ada" Given their simplicity and conciseness, the use of factory functions and Object.create tends to be the preferred approach over the use of constructor functions and the <Constructor>.prototype objects. Object.create <Constructor>.prototype Why is a prototype called a prototype? “Because someone came up with it” is not a satisfactory answer. The word prototype is often glossed over in JavaScript literature. Most people treat it as a technical term and do not explain why it is suitably named “prototype”. Knowing why a prototype is called a prototype can give us a better mental model to work with whenever we encounter it. prototype That being said, it is hard to find an exact answer to this question. Here is my take on this question. A prototype in real life mainly refers to real life A product, albeit with limited features, where the final version of a product will share some characteristics of its prototype. A product, albeit with limited features, where the final version of a product will share some characteristics of its prototype. After substituting the word “product” with “object”, we see that a JavaScript prototype refers to An object, albeit with limited features, where the final version of an object will share some characteristics of its prototype. An object, albeit with limited features, where the final version of an object will share some characteristics of its prototype. Point 1 highlights a distinct point about prototypal inheritance as compared to traditional class-based inheritance. The prototype is an object that can be used on its own. However, a traditional class is not an object and thus cannot be used like an object. Note that although later versions of JavaScript have a class keyword, it still uses prototypal inheritance under the hood. class Point 2 is valid because a prototype typically has fewer properties compared to an object that uses it as its prototype. For example, both alex and Person.prototype are able to greet (although alex does it with the help of Person.prototype ), but alex has an additional name . alex Person.prototype greet alex Person.prototype alex name As for point 3, a JavaScript object does share some characteristics of its prototype(s) because of prototypal inheritance. Since objects are linked in the prototype chain, if you change a prototype, the behavior of existing and future objects linked to that prototype could be affected. As such, be careful not to change a built-in prototype unless you are trying to polyfill a standard feature. If everyone took the liberty of changing built-in prototypes arbitrarily, there will be conflicts and broken code. Summary You have seen what prototypes are, how JavaScript traverses the prototype chain to access prototype properties, and thus how code is reused in what we call prototypal inheritance. You have also seen how to use prototypes, with or without constructor functions. Though the mastery of prototypes has eluded many, I hope that this definitive guide has helped you to master prototypes in JavaScript and thus become a better software developer and engineer. Congratulations for making it all the way here! If you find this guide useful, send it to your colleagues and friends who may benefit from it. For further reading Common Misconceptions About Inheritance in JavaScript by Eric Elliott You Don’t Know JS: this & Object Prototypes by Kyle Simpson Common Misconceptions About Inheritance in JavaScript by Eric Elliott Common Misconceptions About Inheritance in JavaScript You Don’t Know JS: this & Object Prototypes by Kyle Simpson You Don’t Know JS: this this & Object Prototypes