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 constructorsreturn
Only 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 aFunction
objectF
is called, the following steps are taken:
- Create a new native ECMAScript object.
- Set the
[[Class]]
property ofResult(1)
to"Object"
.- Get the value of the prototype property of
F
.- If
Result(3)
is an object, set the[[Prototype]]
property ofResult(1)
toResult(3)
.- If
Result(3)
is not an object, set the[[Prototype]]
property ofResult(1)
to the originalObject
prototype object as described in 15.2.3.1.- Invoke the
[[Call]]
property ofF
, providingResult(1)
as thethis
value and providing the argument list passed into[[Construct]]
as the argument values.- If
Type(Result(6))
isObject
then returnResult(6)
.- Return
Result(1)
.
To sum it up:
- Creates a new object in memory.
- Inside this new object
[[Prototype]]
Property that is assigned to the constructorprototype
Properties. - Constructor
this
Is assigned to this new object (i.ethis
Pointing to a new object). - Executes the code inside the constructor (adding properties to the new object).
- 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:
- A new object inherited from foo. prototype is created.
- 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.
- 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:
- Making instances accessible to private properties;
- Gives instances access to the constructor prototype (
constructor.prototype
) attributes on the prototype chain; - 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.