What is the Prototype in JavaScript and how do they work?

What is the Prototype in JavaScript and how do they work?

In this JavaScript basics tutorial, we'll learn what is a prototype in JavaScript, and how do they work. A prototype is a very beautiful feature in JavaScript since it allows many objects to share data with each other. But, you should be careful to handle the prototype because if you change the prototype, already-created instances have to be updated manually, and it would be easy to make a side-effect.

What is a prototype in JavaScript, and how do they work? In this post, I will talk about prototype in JavaScript.

What Is a Constructor in JavaScript?

To get to know about prototypes, let’s talk about constructors first.

The Constructor function in JavaScript is a function that returns a reference to the object that created the instance object. For example, if your object is an instance of an array, its constructor function refers to the array. This constructor always points to the function itself.

let a = [];
a.constructor === Array; // true

Let’s say there’s a function named Tree. You create a new object, using Tree function:

function Tree() {
  this.name = 'Tree';
}const tree = Tree();
console.dir(tree); // undefined

In the example above, nothing has been stored in tree because Tree doesn’t return any values. In JavaScript, a constructor function is a function object that is only called when the function, Tree, is called with the new keyword.

const tree = new Tree();
console.dir(tree); 

What Is the Prototype in JavaScript

The result of console.dir(tree)

We can see the property name is set after we called Tree with the new keyword. Then what happened when we call a function with new ?

Basically, there are two ways of creating an object by calling a function. The first method is one everybody who knows JavaScript would probably know — just call it like this below.

tree();

Once you call it like that, then the new lexical environment of the function, Tree, will be created, and the JavaScript engine will execute all of the codes inside the tree from the top to the bottom. If there’s a return statement, then tree returns that specific value(s). If there are none, then undefined is returned by default.

However, with new keyword, there are a few steps that the engine takes.

  1. Create an empty object, {} , and assign it to this.
  2. Assign all of the values to this that are expressed like this inside the function. this.name = 'Tree'
  3. return this and store it to a variable that takes the return value of new Tree() .

So, if you call a function with new , the code works like this.

function Tree() {
  this = {};
  this.name = 'Tree';
  return this;
}

How can I know whether the function is called with new?

Since ECMAScript 2015, a new feature came out; new.target. This is a dead-simple feature to let you know if the function is called with new or not. new.target returns a reference to the constructor of the function.

function Tree() {
  if (!new.target) { 
    console.log('Need new !!!');
  }
}Tree(); // Need new !!!
new Tree(); // Tree {}

I understand what constructor is, but why does it matter?

So, if we call Tree with new , then the result looks like this.

function Tree() {
  this.name = 'Tree';
  this.age = 13;
}const tree = new Tree();
// same as
const tree = {
  name: 'Tree';
  age: 13
};

But, imagine that we want to create 10 more trees. If we have to create an object with a literal object every single time, isn’t it a pain in the neck? Simply put every variables or method in a constructor function and create a new object by calling with new . It is not only good to maintain the code, but it’s also reusable.

What is a Prototype?

Let’s talk about the prototype. A prototype is a shared property amongst all the instances of a function object. When a function is invoked with new , a new property called prototype is generated then set to this . One interesting thing is that the constructor of the function itself is a default property of the prototype object. And every object, except for the object created by Object.create(null), has its prototype object. What Is the Prototype in JavaScript

This is what you can see when you make a new instance of Tree. If you aren’t familiar with prototype in JavaScript, just remember this: prototype is merely an object whose property, named constructor, refers to the function that it belongs to.

function Tree(name) {
    this.name = name;
}
Tree.prototype.sayName = function() {
    console.log(this.name);
}

const tree1 = new Tree('Maple');
const tree2 = new Tree('Bamboo');

tree1.sayName(); // Maple
tree2.sayName(); // Bamboo

Although Tree doesn’t have sayName function as its property, tree1 and tree2 have sayName. What Is the Prototype in JavaScript Prototype chain of Tree

This is a full picture of the prototype chains of Tree. I know, it looks so confusing. I will explain it one by one.

  1. Tree has prototype property that is for sharing properties, such as variables and functions, with all of the instances that inherit properties from Tree.
  2. As I mentioned earlier, prototype is just an object that contains constructor function inside, that we talked about earlier in this post. And constructor points to the function itself. Tree’s prototype has constructor that links to Tree function.
  3. Every object includes a certain property named [[prototype]]. It goes by __proto__ in most browsers. What [[prototype]] indicates is the prototype property of an object that the function inherits properties from. For example, look at the picture. Tree’s [[prototype]] refers to Function.prototype because Tree is an instance of Function.
  4. The highest prototype is Object.prototype. Object.prototype doesn’t refer to anything. So Object.prototype.__proto__ is null.
  5. When a variable or a method is called or referred, JavaScript looks for it by looking through all of the prototypes from the very bottom to the very top until it finds what it looks for or it reaches out null from Object.prototype. This process is called Prototype Chain.
tree1.sayName(); // Maple

tree1 doesn’t have sayName as its property.

tree1.hasOwnProperty('sayName'); // false

When sayName is called, JavaScript looks for it within the scope of tree1 , but it can’t find it. Then JavaScript looks for [[prototype]] of tree1 that connects to Tree.prototype . JavaScript can find sayName within the scope of Tree.prototype , and execute it. If there wasn’t sayName in Tree.prototype , then JavaScript, again, looks for [[prototype]] of Tree that connects to Function.prototype . JavaScript keeps doing this until it finds what it was looking for or until it reaches null.

Can I add methods in the prototype even though I already created an object with new?

Absolutely. Look at the example.

function Tree(name) {
    this.name = name;
}
Tree.prototype.sayName = function() {
    console.log(this.name);
}

const tree1 = new Tree('Maple');
const tree2 = new Tree('Bamboo');

tree1.sayName(); // Maple
tree2.sayName(); // Bamboo

// add another method later
Tree.prototype.sayBye = function() {
  console.log(`Bye bye, ${this.name}`); 
}

tree1.sayBye(); // Bye bye, Maple
tree2.sayBye(); // Bye bye, Bamboo

You can add or remove variables or functions in Tree’s prototype anytime you want. All of its instances will dynamically refer to the updated prototype when they try to access it.

Can I replace the prototype?

Sure. You can reassign it with a new prototype object.

function Tree(name) {
    this.name = name;
}
Tree.prototype.sayName = function() {
    console.log(this.name);
}

const tree1 = new Tree('Maple');
const tree2 = new Tree('Bamboo');

tree1.sayName(); // Maple
tree2.sayName(); // Bamboo

Tree.prototype = {
    sayName: function() {
        console.log(`Bye bye, ${this.name}`)
    }
}

const tree3 = new Tree('Ginkgo');

tree1.sayName(); // Maple
tree2.sayName(); // Bamboo
tree3.sayName(); // Bye bye, Ginkgo

As you can see in the result, the prototype of Tree has been changed with a different one, and I made tree3. But the fun part is tree1 and tree2 still point out the previous sayName function that prints this.name , while tree3 points out the new sayName. So this is what you should make sure of before you replace the existing prototype with a new one. Because the existing instances still refer to the original prototype, they won’t work as you expect. Furthermore, GC, Garbage Collector, will not clean the original prototype since it’s still referred by someone else, tree1 and tree2 in this case. So it isn’t considered a best practice to change the prototype.

Conclusion

A prototype is a very beautiful feature in JavaScript since it allows many objects to share data with each other. But, you should be careful to handle the prototype because if you change the prototype, already-created instances have to be updated manually, and it would be easy to make a side-effect. Next post, I will talk about inheritance in JavaScript using the prototype.

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

Brave, Chrome, Firefox, Opera or Edge: Which is Better and Faster?

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

JavaScript Tutorial: if-else Statement in JavaScript

This JavaScript tutorial is a step by step guide on JavaScript If Else Statements. Learn how to use If Else in javascript and also JavaScript If Else Statements. if-else Statement in JavaScript. JavaScript's conditional statements: if; if-else; nested-if; if-else-if. These statements allow you to control the flow of your program's execution based upon conditions known only during run time.

What is “this” in Javascript? | Explaining this keyword in Javascript!

In this JavaScript tutorial, we will learn about what is “this” keyword in JavaScript. You'll understand this and its mechanism, in depth. The this keyword in JavaScript has often been a source of much confusion for beginners to the language.

Building a Powerful Virtual Machine in JavaScript

This JavaScript tutorial explains how to build a powerful Virtual Machine in JavaScript. A flexible, extensible, register-based virtual machine. Support for signed, unsigned and floating point operations. A call stack. Interrupt capabilities. Ability to do memory mapping for IO. An assembly language with macro and module support. A higher level, C like language. We'll use and expand the library from the parser combinators from scratch series. And finally, to be able to take the whole thing into the browser and exend it to create a sort of fantasy console - an emulator for a machine that never existed