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
- Create a temporary object
- Of this temporary object
__proto__
Pointing to the original objectprototype
To enable temporary objects to access properties on the constructor prototype chain - To change the constructor
this
To the temporary object, giving the temporary object access to the constructor’s properties - 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!