手写 new 操作符
1. new 操作符的工作原理
javascript
// new 操作符做了以下4件事:
// 1. 创建一个空对象
// 2. 将这个空对象的原型指向构造函数的 prototype
// 3. 将构造函数的 this 绑定到这个新对象
// 4. 执行构造函数
// 5. 返回这个新对象(如果构造函数没有返回对象,则返回 this)
function Person(name, age) {
this.name = name;
this.age = age;
}
// 使用 new
const p1 = new Person('张三', 25);
2. 手写 myNew 函数
2.1 基础版本
javascript
function myNew(constructor, ...args) {
// 1. 创建一个新对象
const obj = {};
// 2. 将对象的原型指向构造函数的 prototype
obj.__proto__ = constructor.prototype;
// 或者使用:Object.setPrototypeOf(obj, constructor.prototype);
// 3. 将构造函数的 this 绑定到新对象,并执行构造函数
const result = constructor.apply(obj, args);
// 4. 判断构造函数返回值类型
// 如果构造函数返回一个对象,则返回这个对象
// 否则返回新创建的对象
return result instanceof Object ? result : obj;
}
3. 面试常考版本(精简)
javascript
// 面试时能写出的最简版本
function myNew(Con, ...args) {
const obj = Object.create(Con.prototype);
const result = Con.apply(obj, args);
return result instanceof Object ? result : obj;
}
4. 实现原理详解
javascript
// 详细解释每一步
function explainNew(constructor, ...args) {
console.log('1. 获取构造函数:', constructor);
// 步骤1:创建空对象
console.log('2. 创建一个空对象');
const obj = {};
// 步骤2:设置原型链
console.log('3. 设置对象的原型为构造函数的 prototype');
console.log(' 构造函数 prototype:', constructor.prototype);
obj.__proto__ = constructor.prototype;
console.log(' 新对象的 __proto__:', obj.__proto__);
// 步骤3:执行构造函数
console.log('4. 执行构造函数,绑定 this 到新对象');
console.log(' 构造函数参数:', args);
const result = constructor.apply(obj, args);
console.log(' 构造函数返回值:', result);
console.log(' 新对象当前状态:', obj);
// 步骤4:判断返回值
console.log('5. 判断构造函数返回值类型');
const shouldReturnResult = result && (typeof result === 'object' || typeof result === 'function');
console.log(' 应该返回构造函数返回值吗?', shouldReturnResult);
return shouldReturnResult ? result : obj;
}
// 测试
function Demo(name) {
this.name = name;
this.createdAt = new Date();
}
const demo = explainNew(Demo, '测试');
5. 常见面试问题
Q1: new 操作符做了什么?
A:
- 创建一个新对象
- 将这个对象的原型指向构造函数的 prototype
- 将构造函数的 this 绑定到这个新对象,并执行构造函数
- 如果构造函数返回一个对象,则返回这个对象;否则返回新创建的对象
Q2: 手写 new 操作符的思路?
A:
javascript
function myNew(Con, ...args) {
// 1. 创建对象,设置原型
const obj = Object.create(Con.prototype);
// 2. 执行构造函数
const result = Con.apply(obj, args);
// 3. 判断返回值
return result instanceof Object ? result : obj;
}
Q3: 构造函数返回基本类型会怎样?
A: 如果构造函数返回基本类型(string, number, boolean, null, undefined),这个返回值会被忽略,new 操作符会返回新创建的对象。
Q4: 构造函数返回对象会怎样?
A: 如果构造函数返回一个对象(包括数组、函数),那么这个对象会作为 new 表达式的结果,而不是新创建的对象。
Q5: 箭头函数能用 new 调用吗?
A: 不能。箭头函数没有自己的 this,也没有 prototype 属性,所以不能作为构造函数使用。
6. 总结
手写 new 的核心步骤:
- 创建对象:创建一个新对象
- 设置原型 :将对象的
__proto__指向构造函数的prototype - 绑定 this :使用
apply或call将构造函数的 this 绑定到新对象 - 执行构造函数:传入参数执行
- 返回结果:判断构造函数返回值,如果是对象则返回,否则返回新对象
一句话总结:new 操作符就是创建一个新对象,将其原型指向构造函数的 prototype,然后以这个对象为 this 执行构造函数,最后根据构造函数返回值决定返回什么。