Prototypes and Classes in JavaScript
In this blog we will understand prototypes, __proto__ property, "new" keyword, and classes in javascript.
Prerequisite
This blog assumes that you’re somewhat familiar with the objects and this keyword in javascript. If not, then please go through them once.
Introduction
Let's start with objects, so suppose we are building a game where each user object has a username, score, and increment method. So one way to create this object is to have a function that takes all the data creates a new object and returns that object.
It will look like this:
function userCreator(name) {
const userObject = {}
userObject.score = 0,
userObject.username = name,
userObject.incrementScore = function() {
this.score++
}
return userObject
}
const user = userCreator('john')
console.log(user) // {score: 0, username: 'john', incrementScore : ƒ}
This is okay for one or two users, but what about if we have N number of users, this won't be an efficient way to create a new user object, because if you see userCreator function carefully every time it creates a new object with that it also creates a new incrementScore method which is same for all the objects.
So rather than creating a new incrementScore again and again for each object, can't we store it in one place where all the objects created using userCreator function can refer to.
Prototype chain
Using prototype chaining we can solve the above problem let's see. But before that let's dig into objects a little more.
In global memory, there is an Object constructor which is stored as a function + object representation.

Now all the functions in their object representation have the prototype property which itself is an object.

All the objects in javascript have a __proto__ property, which by default has a reference or link or chain to that main window.Object.prototype which is present in global.


So now let's come back to userCreator function, but this time will create the objects using Object.create().
Object.create() creates a new object using other object as its prototype.
So Object.create() takes null or another object, what it does is when an object is created using this method, that object's __proto__ which was by default pointing to the main window.Object kept in global, now will no longer point to that instead it will point to the object which we provided as an argument to Object.create().
KEY POINT: The argument given to the
Object.create()is itself is an object whose__proto__will point to thewindow.Objectwhich is kept in global.
If we give null to the Object.create() as an argument then the object which is created, its __proto__ will no longer have any reference to the window.Object or any other objects.

Let's see an example when we give an object as a argument to the Object.create for userCreator fucntion:
const commonFunctionsObject = {
increment: function() {
this.score++
}
}
function userCreator(name) {
const userObject = Object.create(commonFunctionsObject)
userObject.score = 0
userObject.username = name
return userObject
}
const user = userCreator('john')
console.log(user) // {score: 0, username: 'john'}
But if we see the __proto__ of the user object then we can see that reference.

KEY POINT: So now if you see
userobject carefully then it shows[[Prototype]]where ourcommonFunctionsObjectwas stored. So the[[Prototype]]property is how the__proto__link is indicated in javascript. And[[ ]]aroundPrototypeindicates that it's an internal property that we can't access directly viauser.Prototype

You can also see that there are two [[Prototype]], so what's that second one?
You already know now, as I said commonFunctionsObject is an object whose __proto__ has a link to the main window.Object which is in global memory.

user -> commonFunctionsObject -> window.Object
So if we try to access the increment method on user then first it will look into itself, but it won't find it as it's not there only.
So javascript won't throw an error instead now it will go to its __proto__ link and check that object, in this case, it's commonFunctionsObject over there it will find the increment method and will execute it.
The lookup will look like user then commonFunctionsObject, and this is known as a Prototype chain, the chain which the object will follow to look for any property on it.

"new" keyword
What we see above, the way of creating objects using Object.create and then making there __proto__ point to the object that we pass as an argument to Object.create and then returning the newly created object is what new keyword automates for us.
Let's see an example:
function UserCreator(name, score) {
this.score = score
this.username = name
}
const user = new UserCreator("john", 0)
console.log(user) // {score: 0, username: 'john'}
Now, what is this UserCreator, and how it is different from userCreator from the previous example?, so the first thing you see is the name UserCreator is basically a convention to name the function in capitalize way which indicates to developers that this function is used to create objects using new keyword.
UserCreator function is also called as constructor function.
So when we do const user = new UserCreator("john", 0) the UserCreator function will run:
- It first creates an empty object, and there is
thiswhich is by default present in the memory which will refer to the newly created empty object in the function's memory. - Assigns all the values in the object that we pass and return the object.
- All the objects which are created now will have their
__proto__link to theUserCreator.prototype.

Now if we want to put our shared functions in this case increment, we can put them inside UserCreator.prototype.
function UserCreator(name, score) {
this.score = score
this.username = name
}
UserCreator.prototype.increment = function() {
this.score++
}
const user = new UserCreator("john", 0)

If we create N users then all will refer to this same increment function.

Class
Classes were introduced in ECMAScript 2015 or ES6, now this is not a new thing, it's just syntactic sugar over what we just learned above for new keyword we can say a wrapper around that.
class UserCreator {
constructor(name, score) {
this.score = score
this.username = name
}
increment() {
this.score++
}
}
const user = new UserCreator("john", 0)
console.log(user) // {score: 0, username: 'john'}
Now we write our shared functions inside the wrapper itself i.e class and those functions will be stored in the UserCreator.prototype automatically.

So this is what all the class does.
Summary
- All objects in javascript have the
__proto__property which by default has a link or a chain towindow.Object.prototype. - Functions are stored as a function + its object representation in memory and all function's object representation have a default property called
prototype. newkeyword automates the object creation and linking of their__proto__.classis just a syntactic sugar / a wrapper. Rather than writing the shared functions in the constructor's prototype we directly write them inside the class which automatically stores is in the constructor's prototype.
References
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
- https://frontendmasters.com/courses/?q=javascript
That's it folks I hope you were now able to understand all this.


