The Principle and Implementation of the new Operator in JavaScript
Description
The new operator is used to create an instance of a user-defined object type or of a built-in object with a constructor. It primarily performs the following operations: creates a new object, sets the object's prototype to the constructor's prototype property, executes the constructor function (binding this), and returns the newly created object.
Detailed Steps
-
Basic Usage Example
When usingnew Constructor(), the JavaScript engine implicitly performs the following steps:function Person(name) { this.name = name; } const person = new Person("Alice"); // Instantiation -
Underlying Execution Process
- Step 1: Create a new, empty plain JavaScript object (i.e.,
{}). - Step 2: Set the prototype (
__proto__) of this object to the constructor'sprototypeproperty.// Pseudo code implementation let obj = {}; obj.__proto__ = Constructor.prototype; - Step 3: Execute the constructor function with the object created in Step 1 as the
thiscontext.let result = Constructor.call(obj, ...args); // Pass arguments - Step 4: If the constructor returns an object, return that object; otherwise, return the object created in Step 1.
return result instanceof Object ? result : obj;
- Step 1: Create a new, empty plain JavaScript object (i.e.,
-
Manually Implementing the new Operator
Simulate the behavior of new via a function:function myNew(Constructor, ...args) { // Steps 1 and 2: Create object and bind prototype const obj = Object.create(Constructor.prototype); // Step 3: Execute constructor and bind `this` const result = Constructor.apply(obj, args); // Step 4: Handle return value return result instanceof Object ? result : obj; } -
Edge Case Validation
- When the constructor returns an object:
function Dog() { this.legs = 4; return { name: "Mock" }; // Returning an object overrides default behavior } console.log(new Dog().name); // "Mock" (instead of the `legs` property) - When the constructor returns a primitive value:
function Cat() { this.breed = "Siamese"; return "abc"; // Primitive values are ignored } console.log(new Cat().breed); // "Siamese"
- When the constructor returns an object:
-
Prototype Chain Verification
Objects created via the implementation should correctly inherit prototype methods:Person.prototype.sayHello = function() { console.log(`Hello, I'm ${this.name}`); }; const p = myNew(Person, "Bob"); p.sayHello(); // Should correctly output "Hello, I'm Bob"
Key Points
- The essence of the new operator is a three-step process: connecting the prototype chain, binding
this, and handling the return value. - When implementing manually, note that
Object.createis more standard-compliant than directly setting__proto__. - If the constructor returns a non-object value, the new operation ignores that return value.