Simple implementation
The implementation of the new operator is actually quite simple, because there are only four sentences in Mdn that describe what it does
- Create an empty simple JavaScript object (i.e
{}
); - Add a property proto to the object newly created in Step 1 and link this property to the constructor’s prototype object.
- Take the object created in Step 1 as the object
this
Context; - Returns if the function does not return an object
this
.
Let’s first translate the above four sentences in sequence with the code
Function newOperator() {// create an object const obj = {} // add the attribute __proto__ and point to the Constructor's prototype object obj.__proto__ = constructive.prototype Const ret = constructive.apply (obj, arguments) // If this function does not return an object, Return typeof ret === "object"? ret : obj; }Copy the code
The above code does a fine job of translating the above four sentences, but we can’t use it directly to create an instance of the Constructor because we didn’t pass the Constructor in at all, i.e. the above code won’t run because Constructor isn’t defined
Code is perfect
So let’s reperfect the above code as follows:
- The first new parameter is the constructor that needs the instance
function newOperator(ctor) {}
Copy the code
- Check whether the cTOR parameter type is function or not, otherwise raise an error
if (typeof ctor ! == "function") {throw 'parameter exception, only constructor'}Copy the code
- Create a new instance and add __proto to the object and point to the constructor’s prototype object
// Create an object const obj = {} // add the attribute __proto__ and point to the Constructor's prototype object obj.__proto__ = constructive. prototype // The above code is equivalent to the following code const obj = Object.create(ctor.prototype)Copy the code
- Processing parameters
const params = [].slice.call(arguments, 1)
const result = ctor.apply(obj, params)
Copy the code
Here’s why we need to deal with parameters. Okay
function Dog (name, age) {
this.name = name
this.age = age
}
const maomao = newOperator(Dog, 'maomao', 2)
Copy the code
As you can see from the above code, the first argument to newOperator is the constructor, so we need to truncate the first argument and get [‘maomao’, 2], which are the constructor arguments
- Change this context and get the return result of the construct
const result = ctor.apply(obj, params)
Copy the code
Why get the return result of the construct?
Normally we don’t need a return to implement the constructor, but if we do add the return keyword to the constructor and return the result, we should return the result as well, as shown in the following code
function Cat(name, age) {
return {
name: name,
age: age
}
}
Copy the code
- Determine the type and return
const isObject = typeof result === 'object'
const isFunction = typeof result === 'function'
if (isFunction || isObject) {
return result
}
return obj
Copy the code
The complete code
function newOperator(ctor) { if (typeof ctor ! == "function") {throw ' Constructor '} const obj = object.create (ctor. Prototype) const params = [].slice.call(arguments, 1) const result = ctor.apply(obj, params) const isObject = typeof result === 'object' const isFunction = typeof result === 'function' if (isFunction || isObject) { return result } return obj }Copy the code