What does the `new` keyword do “under the hood” in JavaScript?

Qasim Albaqali
12 min readJul 24, 2020

In this article, we will talk about the different topics that will lead us to understand better what thenew keyword does in JS.

  1. What is the __proto__ property and its role when it comes to objects and the prototypal chaining
  2. What’s the difference between prototype and __proto__
  3. Where in our code do we take advantage of __proto__ and prototype and the prototypal chain
  4. With all the previous knowledge, we will be able to understand the new keyword and how do the different pieces relate to it

The tweet which you can see below is asking whether all Objects have the prototype property [by default]. It sparked a lot of discussions, different answers, and people wondering if what they think is correct or not.

Let me try and answer it in the best way I can. Let’s start with some related topics that will help us to clear the confusion around __proto__, [[Prototype]], and prototype . That will lead us to understand what the new keyword does in JavaScript under the hood.

JavaScript is a prototypal language

One of the cool things about JavaScript is that you can write an application using different programming paradigms such as functional programming and object oriented programming (OOP). The difference between OOP languages such as Java, C#, C++, and the rest of the gang, is that JavaScripts OOP is just syntactical sugar. Under the hood, it makes use of the prototypal chain to allow us as developers to write our application in an OOP style.

Bundling up functions and objects together

Suppose the application we want to create is an e-commerce application. One of the entities that exist in the application is a customer. As a customer, I can add an item to my cart, remove an item, and also checkout/purchase the items that I hold.

Of course, you will have more than one customer registered in your application, and you want all of them to share these functionalities, the ones that we have just defined. Also in the future when our application grows we start having more use cases that we need to add to our customer functionalities.

What’s one way to bundle up multiple functions in one place in JS and save it to be used later again and again? You guessed it, in an Object!

Function are first class citizens in JavaScript

Because functions in JavaScript are first class citizens (objects), it allows us to store functions in a variable, and even in objects as properties which are referred to as methods.

In JavaScript, a function is both a function and an object. As soon as you declare a function in JavaScript it gets an object attached to it directly. You can call it a “function-object combo”. If we use the parentheses myFunc() we are going to access the function form, and if you use the dot notation myFunc.something we will access its object form.

Visualising how a “function-object combo” is stored in memory

The benefit of functions being first class citizens is that we can pass them as arguments to a function, return them from other functions, but also assign them as methods of an object. So let’s start bundling up the customer’s functionality into an object so we can assign it to all of our customers.

const customerOne = {}customerOne.name = "Qasim";
customerOne.items = [];
customerOne.addItem = function (item) {
customerOne.items.push(item);
}
customerOne.removeItem = function (item) { ... }
customerOne.checkout = function () { ... }

As you can see this is tedious to do. You will need to repeat the above code for each customer of your app. Imagine how many developers you have to hire behind the scenes to adjust the above code to create a new customer object for every new user.

Thanks to JavaScripts prototypal feature, we can do this in a better way.

Using the prototypal chain to share functionality

There are different ways to create an object in JS, and the one that we will be focusing on in this section is the Object.create() method. The create method is a built-in method on the Object that whatever you pass into it as an argument will return an empty object. But here is the twist, there is a bonus feature when using the Object.create() that we can get access to, which we will get to it very soon.

So let’s create our first two customers and give them the functionalities that we decided upon as the first use cases of our app using Object.create() .

function customerCreator(name, items = []) {
var newCustomer = Object.create(customerFunctionalities);
newCustomer.name = name;
newCustomer.items = items;
return newCustomer;
}
var customerFunctionalities = {
addItem: function(item) { this.items.push(item); },
removeItem: function(item) { ... },
checkout: function() { .... }
}
var customerOne = customerCreator("Qasim", []);
var customerTwo = customerCreator("Rawan", []);
customerOne.addItem({
name: "You Don't Know JS Yet",
price: "28.30"
});

This seems a lot better than our last example, do you agree?

We are now able not only to create a new customer by just invoking a function, but also attaching different functionalities to them all at one go. Also we have an increase in memory performance and that is because the functions that are attached to the customer objects (methods) are declared once, and all of our customer objects have a link to the functionalities and not directly defined on the objects customerOne and customerTwo .

A link? Remember the bonus feature that I mentioned from using Object.create()?

Let’s break down what exactly happened in the above code. To make it easier and clearer, let’s act like we are the JavaScript runtime, and let’s see how does JavaScript executes the above code in a simplified way.

Let’s run the program

function customerCreator(name, items = []) {
var newCustomer = Object.create(customerFunctionalities);
newCustomer.name = name;
newCustomer.items = items;
return newCustomer;
}
var customerFunctionalities = {
addItem: function(item) { this.items.push(item); },
removeItem: function(item) { ... },
checkout: function() { ... },
}
....

On line 1 we defined the function customerCreator . When JavaScript starts reading our program (parsing phase) it looks at declarations. Both function declarations and variable declarations, and stores them in the memory.

Function decelerations are different than function expressions var myFunc = function () { ... } . Function expressions are seen as variables that have been assigned a function as a value, so JavaScript treats them a bit differently, and that is during the parsing phase (first phase of running a JS program, before the execution) it treats them as variables. Won’t go any deeper on this topic, but something that you might want to read more on about at a later point. At the end, function decelerations and function expressions are identical in the execution phase, so this doesn’t matter much to us right now.

On line 8, we declared a variable customerFunctionalities with an object that holds different properties. The properties of customerFunctionalities are assigned to the function decelerations we passed. Let’s try and visualise how does the global memory of our program looks like at lines 1–8.

Our programs global memory state at line 8

As you can see in the above visualisation, we have two things that are stored, a function definition customerCreator and a variable that holds multiple properties customerFunctionalities. So far so good, but we still haven’t reached the line where we are calling a function.

Things will get more interesting in the next few lines where we really see the power of Object.create() method.

....
var customerOne = customerCreator("Qasim", []);
...

We finally hit a line where we are invoking a function! We have a variable declared named customerOne that is assigned to the result of calling the customerCreator function definition with the arguments "Qasim" and [].When we call/invoke a function in JavaScript, an execution context is created.

An execution context basically is the environment where the function code is being run. The execution context also has its own local memory where it holds the arguments, variables and any other decelerations that are in the functions code during the time it’s being executed.

A new execution context is created when customerCreator is invoked. Arguments are declared to the functions local memory. A new empty object is created using Object.create method and is assigned to the newCustomer variable in the functions local memory.

The thread of execution now enters the execution context of calling customerCreator("Qasim", []) and starts executing line by line until it reaches the end of the function (no more code to run), or if it hits a return statement.

Before executing the first line of the customerCreator function, JavaScript takes care of the arguments that have been passed to the function and stores them in its local memory using the parameter names name: Qasim and items: [] .

On the first line of customerCreator we declared a variable that is assigned to the result of invoking the Object.create method with the argument of customerFunctionalities function definition var customerOne = customerCreator(“Qasim”, []); .

As mentioned earlier, whatever (object or null) is passed as an argument to Object.create it always returns an empty object, but also we get a bonus feature. Object.create returns an empty object and assigns the passed argument to the objects __proto__ hidden property.

As soon as you create an object using Object.create() method an empty object is returned, as well a hidden property is assigned to it called __proto__. You can console.log the returned object and see the __proto__ property, and it should show you that it is referencing customerFunctionalities. This property is also called [[Prototype]] in the JS specification ECMA-262, it’s a link to the reference of the passed object to Object.create where it is stored in the memory. You can think of it as a bond or link.

At the end of the customerCreator, we return out the value of what is stored inside of newCustomer which is an object that contains the name and items properties as well as the __proto__ property that has a bond/link to the customerFunctionalities reference that is stored in the global memory.

The properties of newCustomer name and items are assigned and a reference to the customerFunctionalities object is set in the __proto__ property of the newCustomer object

This is still quite a bit of work. We still have to create two function, one that will return our customer object and another that stores the functionalities we would like our object to link up to and access. We can automate all of this even further.

The “not-so-magical” property of a function — prototype

There is something important that I have left out form the previous sections. When I mentioned how a function in JavaScript is a first class object and it’s a “function-object combo”. As soon as a function is defined and the object is attached to it, a property with the name of prototype is set as a property in its object form. This is done by default by JS on every function that is defined. The default value of prototype is just an empty object.

This gives us a place where we can store more functions that we can create a bond to it and access the functions that we have defined, just like we did using the Object.create() method.

Since prototype is just an object, we can assign it properties.

function customerCreator(name, items) {
....
}
customerCreator.prototype.addItem = function (item) {
this.items.push(item);
}

The “new” keyword comes to the rescue

Finally, after we cleared up all the misconceptions and have a good grasp on how objects and functions behave as well as the prototypal chain, we can finally move on to the last section of this article, and to answer the main question: What does the `new` keyword do “under the hood” in JavaScript?

The answer is very simple. It basically does three things, that we have been doing manually all this time in the previous sections. It will create the customer object for us, attach the functionalities and return the newly created customer object.

Let’s see how our code will look like using the new keyword and visualise what is happening under the hood.

function customerCreator(name, items) {
this.name = name;
this.items = items;
}
customerCreator.prototype.addItem = function (item) {
this.items.push(item);
}
customerCreator.prototype.removeItem = function (item) {
...
}
customerCreator.prototype.checkOut = function () {
...
}
var customerOne = new customerCreator("Qasim", []);customerOne.addItem({
name: "You Don't Know JS Yet",
price: "28.30"
});

Let’s execute the program…

On the following line var customerOne = new customerCreator(“Qasim”, []); a new execution context is created. Even though there is a new keyword before calling the function, JavaScript still treats it as a function invocation, but with a twist.

customerCreator function-object combo are stored in the global memory. A new execution context is created when invoking the new CustomerCreator(..) function

We still haven’t seen anything new right? The function declaration customerCreator is stored in the global memory and the addItem ,removeItem and checkout are set in the prototype property of the function object as method. Now the new keyword comes to play.

The new keyword does three things automatically.

  1. Sets the this variable in the functions local memory to an empty Object. this is called an implicit parameter, and it exists in every function that is invoked.
  2. Sets the __proto__ property of the this to the reference of customerCreator function object prototype property.
  3. Returns the implicit parameter this . Notice how we don’t have an return statement in the customerCreator that is because this is done automatically by the new keyword.
The new keyword in action
  1. The arguments that were passed to customerCreator has been stored in the newly created execution context name: Qasim and items: [] .
  2. The implicit parameter that everything function has by default has been assigned as an empty object at first
  3. The __proto__ property was set to hold the link (reference) to the customerCreator prototype object.
  4. In customerCreator the first two lines of the function is to assign the this object to have two properties this.name and this.items . These properties are assigned to the arguments that were passed "Qasim" and [] . This is not what new automates, this is something that we have written.
  5. The final thing that happens is the this implicit parameter is returned. Since the function invocation is set to the right of an assignment var customerOne = new customerCreator("Qasim, []); it is returned and assigned to the customerOne object that is stored in the global memory.

Alright, so we got things set up, our new customer object has the link to the functionalities that we require. How about now we continue with how the lookup process that happens when customerOne invokes one of the functions that are sitting in the custommerFunctions.prototype object property.

When invoking customerOne.addItem() JS looks inside of the object that is to the left hand side of the . (dot) which in this case is customerOne

  1. Looks in the customerOne object and doesn’t find the method addItem — it doesn’t panic yet
  2. Looks into the __proto__ property of customerOne object and see that it has a link to the customerCreator.prototype which where it finds addItem
  3. Creates a new execution context and invokes the method addItem
  4. In the new execution context, the this implicit parameter is set to the left hand side object customerOne . This happens every time we call a method by using the dot notation, whatever is on the left side of the dot becomes the this implicit parameter
The this implicit parameter is set to the object that is to the left of the dot notation.

Summary

  1. Functions are first class citizens in JavaScript. They can be passed as arguments, assigned to variables, assigned as properties of an object, and can be returned by another function (Higher Order Function)
  2. All functions have an object that you can together you can call them “function-object combo”. The object is created as soon as you defined a function in your code.
  3. Every defined function has a property in it’s object form that is called prototype that is set automatically by JavaScript at the time of definition.
  4. You call/invoke the function part using the parenthesis myFunction() and you can access its object form using the dot notation myFunc.something .
  5. Object.create() ALWAYS creates an empty object, and if it is passed an argument Object.create(myFuncStore) it sets its __proto__ property to have a link/reference to the passed argument.
  6. __proto__ and [[Prototype]] are the exact same thing. The first is the actual Object property name, the latter is the name used to reference it in the ECMA-262 specification
  7. The new keyword does three things. Sets the this implicit parameter in the functions local memory to an empty Object. Creates a link from the implicit parameter this.__proto__ property to the functions prototype. And finally it returns this.
  8. When invoking a method using the dot notation (myObj.objMethod()) in the execution context the this implicit parameter is set to the object that is on the left hand side myObj always.

I hope this was helpful to many of you, and sparked your interested to dive deeper into JavaScript.

Follow me on twitter if you enjoy this type of content @varqasim

Shoutout to Will Sentance for coming up with the “function-object combo” phrase

--

--