手写 new 操作符
实现 JavaScript 中 new 操作符的执行过程
问题
手写实现 new 操作符的执行过程。
解答
new 操作符做了什么
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
const p = new Person('Tom', 18);
执行 new Person('Tom', 18) 时,发生了以下步骤:
- 创建一个空对象
- 将空对象的原型指向
Person.prototype - 执行
Person,this绑定到新对象 - 返回新对象(如果构造函数返回了对象,则返回该对象)
实现 myNew
function myNew(Constructor, ...args) {
// 1. 创建空对象,原型指向构造函数的 prototype
const obj = Object.create(Constructor.prototype);
// 2. 执行构造函数,this 绑定到新对象
const result = Constructor.apply(obj, args);
// 3. 如果构造函数返回对象,则返回该对象;否则返回新创建的对象
return result instanceof Object ? result : obj;
}
测试
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
const p1 = myNew(Person, 'Tom', 18);
console.log(p1.name); // 'Tom'
console.log(p1.age); // 18
p1.sayHi(); // "Hi, I'm Tom"
console.log(p1 instanceof Person); // true
// 测试构造函数返回对象的情况
function Foo() {
this.a = 1;
return { b: 2 };
}
const f = myNew(Foo);
console.log(f.a); // undefined
console.log(f.b); // 2
不用 Object.create 的写法
function myNew(Constructor, ...args) {
// 创建空对象
const obj = {};
// 设置原型
obj.__proto__ = Constructor.prototype;
// 或者用:Object.setPrototypeOf(obj, Constructor.prototype)
// 执行构造函数
const result = Constructor.apply(obj, args);
// 判断返回值
return result instanceof Object ? result : obj;
}
关键点
- 新对象的原型要指向构造函数的
prototype - 用
apply或call绑定this并执行构造函数 - 构造函数返回对象时,
new的结果是该对象,而非新创建的对象 - 构造函数返回基本类型时,忽略返回值,仍返回新对象
Object.create(proto)可以一步完成创建对象和设置原型
目录