new Keyword – What Is the new Operator in JavaScript?
Whenever you use the new
keyword on a constructor, the keyword does the following:
- It creates a new object instance from the constructor.
- It shares the constructor’s
prototype
property with the newly created object.
Syntax of the new
Keyword
We use the new
keyword with a constructor function or class. Here is the syntax:
new Constructor(argument);
You can omit the parentheses if you pass no argument to the constructor.
new Constructor;
Note the following:
- We used an uppercase C in the snippet above because developers typically use capital letters to begin a constructor’s name. This convention helps to differentiate a constructor from other functions.
- You can use the
new
keyword on JavaScript functions or classes. - You can only invoke a JavaScript class with the
new
keyword—otherwise, the browser will throw aTypeError
. - Whatever function (or class) you call with the
new
keyword becomes a constructor function (or class). For instance, thenew createBook
code below makescreateBook
a constructor function.
function createBook() {}const book1 = new createBook();console.log(book1);
The snippet above used the new
keyword to construct a new object from createBook()
. Therefore, the book1
object is an instance of the createBook()
constructor function.
So, now that we know what the new
keyword does, we can discuss how it works.
How Does the new
Keyword Work?
Here’s what happens whenever you use the new
keyword with a constructor:
1. Create empty object
The computer creates an empty JavaScript object in its memory.
{}
2. Add dunder proto
JavaScript adds a dunder ([[Prototype]]
) proto to the newly created object.
{ [[Prototype]]: null}
3. Initialize the dunder proto
The computer initializes the dunder proto with the new object’s constructor’s prototype
.
{ [[Prototype]]: {...}: constructor: keyword ConstructorName() [[Prototype]]: Object {...}}
constructor
references the constructor function (or class) itself.[[Prototype]]
references theprototype
property that the function (or class) inherited from its own constructor.
Therefore, Constructor.prototype
is equivalent to objectInstance.[[Prototype]]
.
Here’s an example:
// Define a constructor function:function CompanyProfile() {}
// Create an object based on the CompanyProfile function:const bestWebsite = new CompanyProfile();
// Check bestWebsite's dunder proto's content:Object.getPrototypeOf(bestWebsite);
// The invocation above will return:{...}: constructor: function CompanyProfile() [[Prototype]]: Object {...}
// Check if CompanyProfile's prototype is equivalent to bestWebsite's dunder proto:CompanyProfile.prototype === Object.getPrototypeOf(bestWebsite);
// The invocation above will return: true
You can see that CompanyProfile.prototype
returned the same value as Object.getPrototypeOf(bestWebsite)
. The reason is that bestWebsite
’s dunder proto contains the prototype
that the object inherited from its constructor (CompanyProfile
).
4. Execute the constructor
The new
operator’s fourth task is to invoke the constructor on which you used it.
5. Bind the constructor’s this
keyword
The computer binds the constructor’s this
keyword to the newly created object.
6. Return a non-primitive value
The computer closes the constructor’s invocation by returning a non-primitive value.
Important Stuff to Know about the new
Keyword
Here are three essential facts to remember when using the new
keyword.
1. Beware of the return
keyword
Suppose your constructor uses the return
keyword to produce an object. In that case, the returned non-primitive value will not inherit the constructor’s prototype
property.
Here’s an example:
// Define a constructor function:function CompanyProfile() { return { name: "CodeSweetly" };}
// Create an object based on the CompanyProfile() constructor:const bestWebsite = new CompanyProfile();
// Check bestWebsite's content:bestWebsite;
// The invocation above will return:{ name: "CodeSweetly";}
// Check if CompanyProfile's prototype is equivalent to bestWebsite's dunder proto:CompanyProfile.prototype === Object.getPrototypeOf(bestWebsite);
// The invocation above will return: false
bestWebsite
did not inherit the CompanyProfile
’s prototype
property because the constructor returned its object using the return
keyword.
Therefore, always omit the return
keyword whenever you want your object instance to inherit its constructor’s prototype
.
Here’s an example:
// Define a constructor function:function CompanyProfile() { this.name = "CodeSweetly";}
// Create an object based on the CompanyProfile() constructor:const bestWebsite = new CompanyProfile();
// Check bestWebsite's content:bestWebsite;
// The invocation above will return:{ name: "CodeSweetly";}
// Check if CompanyProfile's prototype is equivalent to bestWebsite's dunder proto:CompanyProfile.prototype === Object.getPrototypeOf(bestWebsite);
// The invocation above will return: true
The bestWebsite
object instance above inherited the CompanyProfile
’s prototype
property because the constructor did not use the return
keyword to return its object.
2. Always use the new
keyword to invoke constructors
Suppose you invoke your constructor function without the new
keyword. In that case, the constructor will operate like a regular function. Consequently, you may unintentionally create features in the global scope.
Here’s an example:
// Define a function:function CompanyProfile() { this.name = "CodeSweetly";}
// Invoke the CompanyProfile() constructor without using the new keyword:const bestWebsite = CompanyProfile(); // Note the "new" keyword's omission
// Check bestWebsite's name property's value:bestWebsite.name;
// The invocation above will return:// Uncaught TypeError: Cannot read properties of undefined (reading 'name')
// Check if the name property is in the global scope:window.name;
// The invocation above will return: "CodeSweetly"
The window.name
code returned "CodeSweetly"
because the omission of the keyword new
caused the constructor’s this
keyword to reference the global window
object.
3. Use new.target
to confirm if the new
operator invoked a constructor
You can use the new.target
meta-property to verify whether the new
operator invoked a specified constructor.
Suppose the new
operator invoked the constructor. In that case, the new.target
meta-property will return a reference to the constructor. Otherwise, it returns undefined
.
Here’s an example:
// Define a function:function CompanyProfile() { return new.target;}
// Invoke CompanyProfile without the new operator:CompanyProfile();
// The invocation above will return:// undefined
// Invoke CompanyProfile with the new operator:new CompanyProfile();
// The invocation above will return:ƒ CompanyProfile() { return new.target;}
Therefore, you can program your code to behave as a constructor and a regular function like so:
// Define a function:function CompanyProfile() { // If CompanyProfile is a regular function run: if (!new.target) { return { name: "CodeSweetly Tutorials" }; }
// If CompanyProfile is a constructor run: this.name = "CodeSweetly Shop";}
// Invoke CompanyProfile without the new operator:CompanyProfile();
// The invocation above will return:{ name: "CodeSweetly Tutorials";}
// Invoke CompanyProfile with the new operator:new CompanyProfile();
// The invocation above will return:{ name: "CodeSweetly Shop";}