To create a new instance of Person, you must use the new operator. Calling the constructor in this way actually goes through four steps:

  1. Create a new object;
  2. Assign the constructor’s scope to the new object (so this refers to the new object);
  3. Execute the code in the constructor (add attributes to the new object);
  4. Returns a new object;

1. New operator

With the introduction of the basic concepts above, and the addition of the new operator, we can create objects in the traditional object-oriented class + new way, which in JavaScript we call Pseudoclassical.

Based on the example above, we execute the following code

var obj = new Base();
Copy the code

What is the result of such code? The object model we see in Javascript engines is:

What exactly does the new operator do? It’s really simple. It does three things.

varobj = {}; obj.proto = Base.prototype; Base.call(obj); In the first line, we create an empty object obj; In line 2, we point the __proto__ member of this empty object to the Prototype member of the Base function object; On the third line, we add the Base function objectthisReplace the pointer with obj, and then call the Base function, so we assign an ID member variable to the obj object. The value of the member variable is "Base", which is the usage of the call function.Copy the code

What if we added some functions to the Base. Prototype object?

Base.prototype.toString = function() {
   return this.id;
}
Copy the code

So when we use new to create a new object, according to proto’s nature, the toString method can also be used to access the method of the new object.

So here we are:

In prototype we set the public methods of the class. In prototype we set the public methods of the class. The function objects and Javascript’s unique __ proto __ and Prototype members and new operators simulate the effects of classes and class instantiation.

2. What happens in the new operation

For most front-end developers, it is common to create a new constructor or class to get an instance of it. The following example implements a simple instance creation process using the constructor and class classes respectively.

// ES5 constructor
let Dog = function (name, age) {
  this.name = name;
  this.age = age;
};
Dog.prototype.sayName = function () {
  console.log(this.name);
};
const myDog = new Dog('wang wang'.2);
myDog.sayName() // 'bark'

/ / ES6 class class
class Cat {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  sayName() {
    console.log(this.name); }};const myCat = new Cat('QIU'.3);
myCat.sayName(); // QIU
Copy the code

But new should not be like a black box. We should not only know the result, but also understand the process.

Intuitively, when we create a new constructor, the resulting instance inherits the constructor’s constructor properties (this.name and so on) as well as the properties of the prototype.

In the book JavaScript Patterns, the process of new is fairly straightforward. When we create a new constructor, there are three main steps:

  1. Create an empty object and assign its reference to this, inheriting the prototype of the function;
  2. Add attributes and methods to the object with this;
  3. Finally, return the new object to which this points, that is, the instance (if no other object is returned manually);

Rewrite the above example and it looks something like this:

// ES5 constructor
let Dog = function (name, age) {
  // 1. Create a new object and assign this to it. This step is implicit.
  // let this = {};
  // 2. Assign the constructor attribute to the object pointed to by this
  this.name = name;
  this.age = age;
  // 3. If no object is returned manually, the object to which this refers is returned by default, which is also implicit
  // return this;
};
const myDog = new Dog();
Copy the code

This should make sense. You’ve seen code like this at work, which assigns this to a new variable (such as that) and returns the variable

// ES5 constructor
let Dog = function (name, age) {
  let that = this;
  that.name = name;
  that.age = age;
  return that;
};
const myDog = new Dog('wang wang'.2);
Copy the code

Why did you write that?

I mentioned earlier that the creation and return of this are implicit, but in order to make the construction process more visible and maintainable, we use that instead of this and manually return that.

This proves that the implicit two steps really do exist.

However, this explanation is not perfect for me. It only describes how constructor properties are inherited from the instance, not how properties from the prototype are inherited from the instance.

I have seen a description that accords with my mind and principle in winter’s relearning front column:

  • Create a new object based on the constructor’s Prototype property.
  • Pass this (the new object in the previous sentence) and the call parameters to the constructor, and execute;
  • If the constructor does not manually return an object, the object created in the first step is returned;

At this point, however, you should have a general idea of the new process: a new object is created, which inherits the constructor’s prototype and its properties, and is returned as an instance. With that in mind, let’s implement a simple new method manually.

3. Implement a simple new method

// The constructor function
let Dog = function (name, age) {
  this.name = name;
  this.age = age;
};
Dog.prototype.sayName = function () {
  console.log(this.name);
};

// Define the new method
let newMethod = function (Dog, ... rest) {
  // 1. Create a new object using the constructor's prototype property;
  let myDog = Object.create(Dog.prototype);
  // 2. Pass the this and call arguments to the constructor for execution
  Dog.apply(myDog, rest);
  // 3. Return the object of the first step
  return myDog;
};

// Create an instance, passing the constructor Dog and the parameter as arguments
const myDog = newMethod(Dog, 'wang wang'.2);
myDog.sayName() // 'bark ';

// The final check is the same as using new
console.log( myDog instanceof Dog ) // true
console.log( myDog.hasOwnProperty('name'));// true
console.log( myDog.hasOwnProperty('age'));// true
console.log( myDog.hasOwnProperty('sayName'));// false
Copy the code