new 操作符的实现原理可以用以下几个关键步骤来解释:
1. 创建新对象
创建一个空对象,这个对象的内部原型指向构造函数的 prototype 属性。
js
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;
}
2. 完整的手动实现
js
function myNew(Fn, ...args) {
// 1. 创建空对象,设置原型链
const obj = {};
obj.__proto__ = Fn.prototype;
// 2. 执行构造函数,绑定this
const result = Fn.apply(obj, args);
// 3. 处理返回值
// 如果构造函数返回对象,则返回该对象
// 否则返回新创建的对象
return typeof result === 'object' && result !== null ? result : obj;
}
3. 使用示例
js
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};
// 使用自定义的new
const person = myNew(Person, 'Alice', 25);
person.sayHello(); // Hello, I'm Alice
// 对比原生new
const person2 = new Person('Bob', 30);
person2.sayHello(); // Hello, I'm Bob
4. 特殊情况处理
js
function Car(model) {
this.model = model;
// 如果构造函数返回一个对象,new会返回这个对象
return { custom: 'object' };
}
function Bike(model) {
this.model = model;
// 如果返回非对象,会被忽略
return 'string';
}
const car = new Car('Tesla');
console.log(car); // { custom: 'object' }
const bike = new Bike('Yamaha');
console.log(bike); // Bike { model: 'Yamaha' }
5. ES6版本实现
js
function myNew(Constructor, ...args) {
// 创建原型链连接的对象
const instance = Object.create(Constructor.prototype);
// 执行构造函数
const result = Constructor.apply(instance, args);
// 根据返回值决定返回内容
const isObject = typeof result === 'object' && result !== null;
const isFunction = typeof result === 'function';
return isObject || isFunction ? result : instance;
}
关键点总结:
- 创建空对象 :创建新对象,并将其原型指向构造函数的
prototype - 绑定this :将构造函数的
this指向新对象并执行 - 处理返回值 :
- 如果构造函数返回对象,则返回该对象
- 否则返回新创建的对象
- 原型链连接:确保新对象可以访问构造函数原型上的方法
这就是为什么使用 new 调用函数时,函数内部的 this 会指向新对象,并且可以通过原型链访问到构造函数的原型方法。