What is the 'new' keyword in JavaScript?

Viewed 338016

The new keyword in JavaScript can be quite confusing when it is first encountered, as people tend to think that JavaScript is not an object-oriented programming language.

  • What is it?
  • What problems does it solve?
  • When is it appropriate and when not?
16 Answers

Summary:

The new keyword is used in javascript to create a object from a constructor function. The new keyword has to be placed before the constructor function call and will do the following things:

  1. Creates a new object
  2. Sets the prototype of this object to the constructor function's prototype property
  3. Binds the this keyword to the newly created object and executes the constructor function
  4. Returns the newly created object

Example:

function Dog (age) {
  this.age = age;
}

const doggie = new Dog(12);

console.log(doggie);
console.log(Object.getPrototypeOf(doggie) === Dog.prototype) // true

What exactly happens:

  1. const doggie says: We need memory for declaring a variable.
  2. The assigment operator = says: We are going to initialize this variable with the expression after the =
  3. The expression is new Dog(12). The JS engine sees the new keyword, creates a new object and sets the prototype to Dog.prototype
  4. The constructor function is executed with the this value set to the new object. In this step is where the age is assigned to the new created doggie object.
  5. The newly created object is returned and assigned to the variable doggie.

There are already some very great answers but I'm posting a new one to emphasize my observation on case III below about what happens when you have an explicit return statement in a function which you are newing up. Have a look at below cases:

Case I:

var Foo = function(){
  this.A = 1; 
  this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1

Above is a plain case of calling the anonymous function pointed by Foo. When you call this function it returns undefined. Since there is no explicit return statement so JavaScript interpreter forcefully inserts a return undefined; statement in the end of the function. Here window is the invocation object (contextual this) which gets new A and B properties.

Case II:

var Foo = function(){
  this.A = 1;
  this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1

Here JavaScript interpreter seeing the new keyword creates a new object which acts as the invocation object (contextual this) of anonymous function pointed by Foo. In this case A and B become properties on the newly created object (in place of window object). Since you don't have any explicit return statement so JavaScript interpreter forcefully inserts a return statement to return the new object created due to usage of new keyword.

Case III:

var Foo = function(){
  this.A = 1;
  this.B = 2;
  return {C:20,D:30}; 
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.

Here again JavaScript interpreter seeing the new keyword creates a new object which acts as the invocation object (contextual this) of anonymous function pointed by Foo. Again, A and B become properties on the newly created object. But this time you have an explicit return statement so JavaScript interpreter will not do anything of its own.

The thing to note in case III is that the object being created due to new keyword got lost from your radar. bar is actually pointing to a completely different object which is not the one which JavaScript interpreter created due to new keyword.

Quoting David Flanagan from JavaScripit: The Definitive Guide (6th Edition),Ch. 4, Page # 62:

When an object creation expression is evaluated, JavaScript first creates a new empty object, just like the one created by the object initializer {}. Next, it invokes the specified function with the specified arguments, passing the new object as the value of the this keyword. The function can then use this to initialize the properties of the newly created object. Functions written for use as constructors do not return a value, and the value of the object creation expression is the newly created and initialized object. If a constructor does return an object value, that value becomes the value of the object creation expression and the newly created object is discarded.

Additional Info

The functions used in code snippet of above cases have special names in JS world as below:

Case # Name
Case I Constructor function
Case II Constructor function
Case III Factory function

You can read about difference between constructor function and factory function in this thread.

Note about case III - Factory functions shouldn't be used with new keyword which I've shown in the code snippet above. I've done so deliberately just to explain the concept in this post.

The new keyword changes the context under which the function is being run and returns a pointer to that context.

When you don't use the new keyword, the context under which function Vehicle() runs is the same context from which you are calling the Vehicle function. The this keyword will refer to the same context. When you use new Vehicle(), a new context is created so the keyword this inside the function refers to the new context. What you get in return is the newly created context.

 " Every object (including functions) has this internal property called [[prototype]]" 

Every function has a proto- type object that’s automatically set as the prototype of the objects created with that function.

you guys can check easily:

const a = { name: "something" };
console.log(a.prototype); // undefined because it is not directly accessible

const b = function () {
  console.log("somethign");};

console.log(b.prototype); // returns b {}

But every function and objects has __proto__ property which points to the prototype of that object or function. __proto__ and prototype are 2 different terms. I think we can make this comment: "Every object is linked to a prototype via the proto " But __proto__ does not exist in javascript. this property is added by browser just to help for debugging.

console.log(a.__proto__); // returns {}
console.log(b.__proto__); // returns [Function]

You guys can check this on the terminal easily. So what is constructor function.

function CreateObject(name,age){
    this.name=name;
    this.age =age
}

5 things that pay attention first:

1- When constructor function is invoked with new, the function’s internal [[Construct]] method is called to create a new instance object and allocate memory.

2- We are not using return keyword. new will handle it.

3- Name of the function is capitalized so when developers see your code they can understand that they have to use new keyword.

4- We do not use arrow function. Because the value of the this parameter is picked up at the moment that the arrow function is created which is "window". arrow functions are lexically scoped, not dynamically. Lexically here means locally. arrow function carries its local "this" value.

5- Unlike regular functions, arrow functions can never be called with the new keyword because they do not have the [[Construct]] method. The prototype property also does not exist for arrow functions.

const me=new CreateObject("yilmaz","21")

new invokes the function and then creates an empty object {} and then adds "name" key with the value of "name", and "age" key with the value of argument "age".

When we invoke a function, a new execution context is created with "this" and "arguments", that is why "new" has access to these arguments.

By default this inside the constructor function will point to the "window" object, but new changes it. "this" points to the empty object {} that is created and then properties are added to newly created object. If you had any variable that defined without "this" property will no be added to the object.

function CreateObject(name,age){
    this.name=name;
    this.age =age;
    const myJob="developer"
}

myJob property will not added to the object because there is nothing referencing to the newly created object.

   const me= {name:"yilmaz",age:21} // there is no myJob key

in the beginning I said every function has "prototype" property including constructor functions. We can add methods to the prototype of the constructor, so every object that created from that function will have access to it.

 CreateObject.prototype.myActions=function(){ //define something}

Now "me" object can use "myActions" method.

javascript has built-in constructor functions: Function,Boolean,Number,String..

if I create

const a = new Number(5);
console.log(a);  // [Number: 5]
console.log(typeof a); // object

Anything that created by using new has type of object. now "a" has access all of the methods that are stored inside Number.prototype. If I defined

const b = 5;
console.log(a === b);//false

a and b are 5 but a is object and b is primitive. even though b is primitive type, when it is created, javascript automatically wraps it with Number(), so b has access to all of the methods that inside Number.prototype.

Constructor function is useful when you want to create multiple similar objects with the same properties and methods. That way you will not be allocating extra memory so your code will run more efficiently.

Javascript is not object oriented programming(OOP) language therefore the LOOK UP process in javascript work using 'DELEGATION PROCESS' also known as prototype delegation or prototypical inheritance.

If you try to get the value of a property from an object that it doesn't have, the JavaScript engine looks to the object's prototype (and its prototype, 1 step above at a time) it's prototype chain untll the chain ends upto null which is Object.prototype == null (Standard Object Prototype). At this point if property or method is not defined than undefined is returned.

Imp!! Functions are functions are first-class objects

Functions = Function + Objects Combo

FunctionName.prototype = { shared SubObject }

{
  // other properties
  prototype: {  
   // shared space which automatically gets [[prototype]] linkage 
      when "new" keyword is used on creating instance of "Constructor 
      Function"
  }
}

Thus with the new keyword some of the task that were manually done e.g

  1. Manual Object Creation e.g newObj.
  2. Hidden bond Creation using proto (aka: dunder proto) in JS spec [[prototype]] (i.e. proto)
  3. referencing and assign properties to newObj
  4. return of newObj object.

All is done manually.

function CreateObj(value1, value2) {
  const newObj = {};
  newObj.property1 = value1;
  newObj.property2 = value2;
  return newObj;
}
var obj = CreateObj(10,20);

obj.__proto__ === Object.prototype;              // true
Object.getPrototypeOf(obj) === Object.prototype // true

Javascript Keyword new helps to automate this process:

  1. new object literal is created identified by this:{}
  2. referencing and assign properties to this
  3. Hidden bond Creation [[prototype]] (i.e. proto) to Function.prototype shared space.
  4. implicit return of this object {}
function CreateObj(value1, value2) {
  this.property1 = value1;
  this.property2 = value2;
}

var obj = new CreateObj(10,20);
obj.__proto__ === CreateObj.prototype             // true
Object.getPrototypeOf(obj) == CreateObj.prototype // true

Calling Constructor Function without the new Keyword:

=> this: Window

function CreateObj(value1, value2) {
  var isWindowObj = this === window;
  console.log("Is Pointing to Window Object", isWindowObj);
  this.property1 = value1;
  this.property2 = value2;
}
var obj = new CreateObj(10,20); // Is Pointing to Window Object false
var obj = CreateObj(10,20); // Is Pointing to Window Object true
window.property1; // 10
window.property2; // 20

Related