This is the 8th day of my participation in the August More Text Challenge. For details, see:August is more challenging

define

The new operator creates an instance of a user-defined object type or an instance of a built-in object with a constructor.

Use the new [constructor] approach to create an object instance, but the constructor difference will result in different instances being created.

Constructor bodies are different

Constructors are functions. The only difference is how they are called. Any function called with the new operator is a constructor, and any function called without the new operator is a normal function.

So the constructor can also have a return value, but that would result in a different result for new.

There is no return value

function Person(name) {
  this.name = name;
}

let obj = new Person("Jalenl");
console.log(obj);
Copy the code

Obviously, it prints {name:’Jalenl’}

Returns the object

function Person(age) {
  this.age = age;
  return { name: "Jalenl" };
}

let obj = new Person(18);
console.log(obj);
Copy the code

It prints {name:’Jalenl’}, which means that all definitions before return are overwritten. If I return an object, what if I return a primitive type?

Return non-object

function Person(age) {
  this.age = age;
  return 1;
}

let obj = new Person(18);
console.log(obj);
Copy the code

Return {age:21}, so return is invalid, as if there were no return. What if there were no internal attribute bound to this, and then the basic data type was returned?

No property binding + returns non-object

function Person(){
    return 1
}
new Person()
Copy the code

An empty object {} is returned, not surprisingly.

In summary, there are only constructorsreturnOnly when an object type is returned can the initial result be changed.

Constructor types are different

The constructor is an ordinary function

Ecma-262 3rd. Edition Specification ecMA-262 3rd. Edition Specification

13.2.2 [[the Construct]]

When the [[Construct]] property for a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
  6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
  7. If Type(Result(6)) is Object then return Result(6).
  8. Return Result(1).

To sum it up:

  1. Creates a new object in memory.
  2. Inside this new object[[Prototype]]Property that is assigned to the constructorprototypeProperties.
  3. ConstructorthisIs assigned to this new object (i.ethisPointing to a new object).
  4. Executes the code inside the constructor (adding properties to the new object).
  5. If the constructor returns an object, that object is returned; Otherwise, the newly created (empty) object is returned.

Step 5 shows how different constructors cause different results for new.

The following is an excerpt from MDN’s explanation:

When the code new Foo(…) When executed, the following happens:

  1. A new object inherited from foo. prototype is created.
  2. Calls the constructor Foo with the specified arguments and binds this to the newly created object. New Foo is the same as new Foo(), that is, when no argument list is specified and Foo is called with no arguments.
  3. The object returned by the constructor is the result of the new expression. If the constructor does not explicitly return an object, the object created in Step 1 is used. (Normally, constructors do not return values, but users can choose to actively return objects to override the normal object creation steps.)

The constructor is the arrow function

When a normal function is created, the engine creates a Prototype property (pointing to the prototype object) for the function according to specific rules. By default, all prototype objects automatically get a property called constructor, which refers back to the constructor associated with them.

function Person(){
    this.age = 18;
}
Person.prototype
/ * * {constructor: ƒ Foo () __proto__ : Object} * * /
Copy the code

When creating an arrow function, the engine does not create a prototype property for it. There is no constructor for the arrow function to be called by new.

const Person = () = >{}
new Person()//TypeError: Foo is not a constructor
Copy the code

Write a new

To sum up, after we are familiar with the working principle of new, we can implement a low version of New by ourselves. The key is:

  1. Making instances accessible to private properties;
  2. Gives instances access to the constructor prototype (constructor.prototype) attributes on the prototype chain;
  3. The final result returned by the constructor is the reference data type.
function _new(constructor, ... args) {
    // The constructor type is valid
    if(typeof constructor! = = 'function') {
      throw new Error('constructor must be a function');
    }
    // Create an empty object instance
    let obj = new Object(a);// Bind the constructor stereotype to the newly created object instance
    obj.__proto__ = Object.create(constructor.prototype);
    // Call the constructor and determine the return value
    let res = constructor.apply(obj, args);
    let isObject = typeof res === 'object'&& res ! = =null;
    let isFunction = typeof res === 'function';
    // If there is a return value and the return value is an object type, then it is returned, otherwise the previously created object is returned
    return isObject || isFunction ? res : obj;
};
Copy the code

This lower-level new implementation can be used to create instances of custom classes, but built-in objects are not supported. After all, new is an operator and the underlying implementation is more complex.