Before we implement the new operator, let’s look at what the new operator does and what it does

New operator

To quote the explanation on MDN

The new operator is used to create an instance of a user-defined object or a built-in object instance with a constructor

Simply put, the new operator is used to create an instance of an object.

function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
}

const car1 = new Car('Eagle'.'Talon Tsi'.1993);

// Verify that the instance can access the properties of the constructor
console.log(car1.make);
// Eagle

// We perform a validation on CAR1
// Verify that the instance has access to the constructor's prototype chain
car1.__proto__ === Car.prototype;  // true
car1.constructor === Car  // true
Car.prototype.constructor === Car // true
Copy the code

So the main function of the new operator is:

  • Give instances access to constructor properties
  • Gives the instance access to the constructor’s original necklace

Implement a simple new

According to the above decomposition, let’s organize the simple idea

  1. Create a temporary object
  2. Of this temporary object__proto__Pointing to the original objectprototypeTo enable temporary objects to access properties on the constructor prototype chain
  3. To change the constructorthisTo the temporary object, giving the temporary object access to the constructor’s properties
  4. Returns this new object
function _new(Obj, ... args) {
    var tmp = {};  Create a temporary object
    tmp.__proto__ = Obj.prototype;  // The temporary object __proto__ points to the constructor prototype. The temporary object has access to the properties of the constructor prototypeObj.call(tmp, ... args);// Change the constructor's this to the temporary object so that the temporary object can access the constructor's properties
    return tmp;  // Return this temporary object
}
Copy the code

Now you can copy this simple function to the console to verify:

function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
}

const car1 = _new(Car, 'Eagle'.'Talon Tsi'.1993);

car1 instanceof Car // true
car.__proto__ === Car.prototype  // true
car1.constructor === Car  // true
Car.prototype.constructor === Car // true
Copy the code

Verify that the pull has passed

further

The previous section did a simple implementation of the new operator, but did not consider more scenarios. What if the constructor had a return value?

For example, the constructor itself returns an object

function _new(Obj, ... args) {
    vartmp = {}; tmp.__proto__ = Obj.prototype; Obj.call(tmp, ... args);return tmp;
}

function Car(make, model, year) {
    this.make = make;

    return {
        model,
        year
    };
}

var car1 = _new(Car, 'a'.'b'.'c');

console.log(car1.make)  // a
console.log(car1.model)  // undefined
console.log(car1.year);  // undefined
Copy the code

In this case, the constructor returns an object, but the instance cannot read it at all, so we need to make a judgment as to whether the constructor return is an object

Modify the previous version of the code:

function _new(Obj, ... args) {
    var tmp = {};
    tmp.__proto__ = Obj.prototype;
    constret = Obj.call(tmp, ... args);return typeof ret === 'object' ? ret : tmp;  // Determine if the constructor returns an object, if it is, return the object, otherwise return a temporary object
}
Copy the code

The final version is complete!