[toc]

Analysis: What does New do

The new operator generates an instance object by executing either a custom constructor or a built-in JS constructor.

In MDN, the internal operation is roughly divided into four steps:

  1. Create an empty simple JavaScript object (that is {});
  2. Link this object (that is, set its constructor) to another object;
  3. Use the new object created in Step 1 as the context for this;
  4. If the function does not return an object, this is returned.

Walk through the above steps with a simple demo

function Person (name){
    this.name = name
}
let p = new Person('jack');
console.log(`p:`, p); // { name: 'jack' }
console.log(`p.__proto__===Person.prototype:`,p.__proto__===Person.prototype);  //true
Copy the code

You can see that after executing the Person constructor, the new operator returns a new object created internally, executes the Person function on that object as the context for the post, and returns it, with the prototype property of object P pointing to the prototype of the constructor. This ensures that the instance can access the properties and methods defined in the constructor prototype.

In the demo above, constructors do not return values. What if constructors return values

function Person (name){
    this.name = name;
    return {age: 18}}let p = new Person('jack');
console.log(`p:`, p); // { age: 18 }
Copy the code

If the constructor returns an object at the end, it returns it directly, rather than creating a new object internally.

After tests found, in addition to return objects, if return to the other types, as long as the return type is a reference type object or function (function, object, Array, the Date, the Error, the Regexp, to exclude null, Because typeof NULL === ‘object’) returns it directly, and all other primitive types return internally newly created objects.

Custom implementation

Here we try to mimic the main function of the new operator by encapsulating a myNew method: it takes several arguments, the first of which is the constructor CTR, and the rest are the arguments required by the constructor, myNew(CTR, arg1, arg2…).

The first step

The first step here puts together steps 1 and 2 in MDN: create a new object and point its __proto__ attribute to the constructor’s Prototype attribute

function myNew(ctr) {
    let obj = Object.create(ctr.prototype);
}
Copy the code

You can also use the following methods

function myNew (ctr){
    let obj = {};
    obj.__proto__ = ctr.prototype;
}
Copy the code

The second step

After the parameters are obtained, the constructor is executed to assign a value to the newly created object obj as the thread

function myNew(ctr) {
    let obj = Object.create(ctr.prototype);
    
    const args = [].slice.call(arguments.1);
    let result = ctr.apply(obj, args);
    console.log(`obj:`,obj);
}
Copy the code

Const args = [].slice.call(arguments, 1); Use array.form (arguments).slice(1) or […arguments].slice(1).

The third step

The constructor returns the value result. If the constructor eventually returns other reference types such as object, function, array, date, and Symbol, they are returned directly. The other primitive types, null, and undefined, return the internally created instance of the object.

function myNew(ctr) {
    let obj = Object.create(ctr.prototype);

    const args = [].slice.call(arguments.1);
    let result = ctr.apply(obj, args);

    var isObj = (typeof result === 'object'&& result ! = =null);
    var isFn = typeof result === 'function';
    return (isObj || isFn) ? result : obj;
}
Copy the code

test

Finally, simply test that there is no return value

function Person(name) {
    this.name = name;
}
let p = myNew(Person,'jack');
console.log(`p:`,p);
Copy the code

Returns a value

function Person(name) {
    this.name = name;
    return {age: 33}}let p = myNew(Person,'jack');
console.log(`p:`,p);
Copy the code

reference

Can you manually implement a new operator understanding that mimics implementing JS’s new operator