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

  1. Create an empty simple JavaScript object (i.e {} );
  2. Add a property proto to the object newly created in Step 1 and link this property to the constructor’s prototype object.
  3. Take the object created in Step 1 as the objectthisContext;
  4. Returns if the function does not return an objectthis.

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