introduction
We know thatES6
Before(ES5
),JavaScript
The manifestation of the class in the class is the constructor.
JavaScript
What is the constructor in it?
- The constructor is alsoNormal functions, from the perspective of expression, is no different from ordinary functions (except as convention, the first letter of the constructor name is usually capitalized);
- But if a normal function is called by the new operator, then this function is calledConstructor;
principle
If a function isnew
The operator is called, then it will perform the following operations:
- Create a new object in memory;
- Put the new object inside
[[Prototype]]
Assigning attribute values to constructorsprototype
property; - Put the constructor inside
this
Assign value to this new object (i.e.this
point to a new object); - Execute code inside the constructor (add attributes to the new object);
- If the constructor returns a non-empty object, it returns the object; otherwise, it returns the new object just created;
Handwritten function simulation new
Next, based on the above principle, we try to write a function by hand and simulate the implementation.new
Function of operator.
Basic implementation of v1
Let's use it firstES5
syntax to implement:
function useNewOperator() { var constructor = arguments[0] var args = [].(arguments, 1) // 1. Create a new object in memory var obj = {} // 2. The [[Prototype]] pointer inside this new object is assigned as the prototype property of the constructor obj.__proto__ = // 3. This inside the constructor is assigned to this new object (that is, this points to the new object) // 4. Execute the code inside the constructor (add attributes to the new object) var res = (obj, args) // 5. If the constructor returns a non-empty object, it will return the object; otherwise, return the new object just created if (res != null && (typeof res === 'object' || typeof res === 'function')) { return res } return obj } // testfunction Person(name, age) { = name = age // return undefined // return null // return {} // return 123 // return '' // return String(123) // return new String(123) // return { name: 'wy' } } = function() { (); } const p1 = new Person('zhj', 20) (p1); // Person {name: 'zhj', age: 20} () // zhj const p2 = useNewOperator(Person, 'zhj', 20) (p2); // Person {name: 'zhj', age: 20} () // zhj
v2 Consider parameter types
The above basic implementation can run, but there are still problems, that is, it does not consider whether the first parameter is a function type. If the first parameter is passed in is not a function, then it is executed.(obj, args)
This line of code callsconstructor()
There will be an error when it is. So we need to add a judgment. If the first parameter passed in is not a function, then the exception will be thrown directly:
function useNewOperator() { var constructor = arguments[0] + + if (typeof constructor !== 'function') { + throw new TypeError('the first argument to useNewOperator function must be a function') + } + var args = [].(arguments, 1) // 1. Create a new object in memory var obj = {} // 2. The [[Prototype]] pointer inside this new object is assigned as the prototype property of the constructor obj.__proto__ = // 3. This inside the constructor is assigned to this new object (that is, this points to the new object) // 4. Execute the code inside the constructor (add attributes to the new object) var res = (obj, args) // 5. If the constructor returns a non-empty object, it will return the object; otherwise, return the new object just created if (res != null && (typeof res === 'object' || typeof res === 'function')) { return res } return obj } // testfunction Person(name, age) { = name = age } = function() { (); } const obj = {} const p2 = useNewOperator(obj, 'zhj', 20) // Uncaught TypeError: the first argument to useNewOperator function must be a function (p2); ()
Alternatives to v3 .__proto__
We were putting the new object inside[[Prototype]]
Assigning attribute values to constructorsprototype
When attributes are givenobj
On__proto__
The attribute assignment is implemented (equivalent to using.__proto__
), although ok, it is not recommended to use.__proto__
, more recommended/
and/
(Reference link:/zh-CN/docs/…). So we make the following modifications:
function useNewOperator() { var constructor = arguments[0] if (typeof constructor !== 'function') { throw new TypeError('the first argument to useNewOperator function must be a function') } var args = [].(arguments, 1) // 1. Create a new object in memory var obj = {} // 2. The [[Prototype]] pointer inside this new object is assigned as the prototype property of the constructor+ (obj, ) // 3. This inside the constructor is assigned to this new object (that is, this points to the new object) // 4. Execute the code inside the constructor (add attributes to the new object) var res = (obj, args) // 5. If the constructor returns a non-empty object, it will return the object; otherwise, return the new object just created if (res != null && (typeof res === 'object' || typeof res === 'function')) { return res } return obj } // testfunction Person(name, age) { = name = age } = function() { (); } const p1 = new Person('zhj', 20) (p1); // Person {name: 'zhj', age: 20} () // zhj const p2 = useNewOperator(Person, 'zhj', 20) (p2); // Person {name: 'zhj', age: 20} () // zhj
Or we can use it()
Directly specify the prototype to create a new object:
function useNewOperator() { var constructor = arguments[0] if (typeof constructor !== 'function') { throw new TypeError('the first argument to useNewOperator function must be a function') } var args = [].(arguments, 1) // 1. Create a new object in memory- var obj = {} - // 2. The [[Prototype]] pointer inside this new object is assigned as the prototype property of the constructor+ var obj = () // 3. This inside the constructor is assigned to this new object (that is, this points to the new object) // 4. Execute the code inside the constructor (add attributes to the new object) var res = (obj, args) // 5. If the constructor returns a non-empty object, it will return the object; otherwise, return the new object just created if (res != null && (typeof res === 'object' || typeof res === 'function')) { return res } return obj } // testfunction Person(name, age) { = name = age } = function() { (); } const p1 = new Person('zhj', 20) (p1); // Person {name: 'zhj', age: 20} () // zhj const p2 = useNewOperator(Person, 'zhj', 20) (p2); // Person {name: 'zhj', age: 20} () // zhj
v4 implements using ES6 syntax
Next, let's use it againES6
Syntax (remaining parameters (rest parameters
)、const
) Implementation:
function useNewOperator(constructor, ...args) { if (typeof constructor !== 'function') { throw new TypeError('the first argument to useNewOperator function must be a function') } // 1. Create a new object in memory const obj = {} // 2. The [[Prototype]] pointer inside this new object is assigned as the prototype property of the constructor (obj, ) // Or use () to directly specify the prototype to create a new object // const obj = () // 3. This inside the constructor is assigned to this new object (that is, this points to the new object) // 4. Execute the code inside the constructor (add attributes to the new object) const res = (obj, args) // 5. If the constructor returns a non-empty object, it will return the object; otherwise, return the new object just created if (res != null && (typeof res === 'object' || typeof res === 'function')) { return res } return obj } // testfunction Person(name, age) { = name = age } = function() { (); } const p1 = new Person('zhj', 20) (p1); // Person {name: 'zhj', age: 20} () // zhj const p2 = useNewOperator(Person, 'zhj', 20) (p2); // Person {name: 'zhj', age: 20} () // zhj
v5 considers ES6 detection
Finally, there is another point to consider, that isES6
Newly addedAttributes, in use
new
In the constructor or function in which the operator is called,Returns a reference to the constructor method or function (reference link:/en-US/docs/…). So we can use
To detect whether a function or constructor passes
new
The operator is called. Then we still need to implement it ourselvesuseNewOperator
Add the corresponding code to the function:
Uncommented version
function useNewOperator(constructor, ...args) { if (typeof constructor !== 'function') { throw new TypeError('the first argument to useNewOperator function must be a function') } = constructor const obj = {} (obj, ) // const obj = () const res = (obj, args) if (res != null && (typeof res === 'object' || typeof res === 'function')) { return res } return obj }
The above is aboutnew
The principle behind the operation and the simulation implementation of handwritten functionsnew
All the contents of the operation process. For more information about JS new operating handwritten functions, please follow my other related articles!