# 模拟实现new运算符
其实new操作符很简单,直白说,就是创建一个有指定属性的对象并返回给我们而已。
仔细分析这句话,它就三点意思:
- 创建对象
- 包含指定属性
- 返回属性
new操作符是通过构造函数来生成实例对象。分析清楚实例、构造函数、原型这三者的关系是很重要的。
以下是我对三者的关系归纳:
实例的
__proto__和构造函数的prototype可以理解为等价的,他们都指向原型。也就是说实例的原型和构造函数的原型指向同一个对象。
等同如下语句:
function Person(name,age){
this.name = name;
this.age = age;
}
let person1 = new Person("Jack",25);
person1.__proto__ === Person.prototype // true
// person1实例的__proto__ 和 Person构造函数的prototype 指向同一个对象,那就是 原型。
仔细研究下面的图片:

现在开始模拟实现new操作符。
我们要实现的最终效果是一个工厂函数,这个工厂函数通过我们传入的构造函数和其他属性值来生成我们想要的对象。
该工厂函数的外观如下:
function myNewFactory(Constructor,...args){
// new 操作符的核心块
}
第一步: 创建对象
function myNewFactory(Constructor,...args){
// 1. 生成对象
let obj = Object.create(Object.prototype) // 其实等价于 let obj = {} 啦。
}
第二步: 给生成的对象绑定属性
属性包括构造函数自身的属性和构造函数原型上的属性。
function myNewFactory(Constructor,...args){
// 1. 生成对象
let obj = Object.create(Object.prototype) // 其实等价与 let obj = {} 啦。
// 2.1 绑定构造函数原型上的属性
obj.__proto__ = Constructor.prototype;
// 2.2 绑定构造函数自身的属性
Constructor.apply(obj,args);
}
第三步: 返回对象
function myNewFactory(Constructor,...args){
// 1. 生成对象
let obj = Object.create(Object.prototype) // 其实等价与 let obj = {} 啦。
// 2.1 绑定构造函数原型上的属性
obj.__proto__ = Constructor.prototype;
// 2.2 绑定构造函数自身的属性
Constructor.apply(obj,args);
// 3 返回对象
return obj
}
以上其实就做完了。只是还可以优化而已,但那都不是核心。
完善的点: 如果构造函数是以下两种情况,需要特别处理。
- 构造函数返回对象
function Otaku (name, age) {
this.strength = 60;
this.age = age;
return {
name: name,
habit: 'Games'
}
}
var person = new Otaku('Kevin', '18');
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // undefined
console.log(person.age) // undefined
// 构造函数返回了一个对象,在实例 person 中只能访问返回的对象中的属性。
- 构造函数返回基本类型
function Otaku (name, age) {
this.strength = 60;
this.age = age;
return 'handsome boy';
}
var person = new Otaku('Kevin', '18');
console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.strength) // 60
console.log(person.age) // 18
// 返回基本类型,相当于没有进行返回
完善后的最终代码:
function myNewFactory(Constructor,...args){
let obj = Object.create(Object.prototype);
obj.__proto__ = Constructor.prototype;
let ret = Constructor.apply(obj,args);
return typeof ret === "object" ? ret : obj;
}