new 操作,我们在类对象,函数中都会使用到,那么它到底是用来干什么的呢?又是怎么实现的呢?
第一版 - 基础完成
我们先看看 MDN 的定义:
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
我们先来举个例子吧
1 2 3 4 5 6 7 8 9 10 11 12 13
| function Person(name, age) { this.name = name; this.age = age; } Person.prototype.weight = 70; Person.prototype.getInfo = function () { console.log(this.name, this.age, this.weight); }; const person = new Person('hzzzzzzzq', 18); console.log(person.name); console.log(person.age); console.log(person.weight); person.getInfo();
|
我们从例子中来看,我们创建的实例 person 可以做到
所以由此我们来推断 new 操作做了什么。
- new 的返回时一个对象
- 需要为对象添加属性
- 需要将对象原型指向构造函数的原型
但是由于 new
操作是关键字,所以就是用一个创建方法 objectFactory
来替代了。
1 2 3 4 5
| let pserson = new Person(...arguments);
let person = objectFactory(Person, ...arguments);
|
由此,我们来看第一版代码吧。
1 2 3 4 5 6 7
| function objectFactory() { const obj = {}; const Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; Constructor.apply(obj, arguments); return obj; }
|
接下来,我们来测试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function Person(name, age) { this.name = name; this.age = age; } Person.prototype.weight = 70; Person.prototype.getInfo = function () { console.log(this.name, this.age, this.weight); };
function objectFactory() { const obj = {}; const Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; Constructor.apply(obj, arguments); return obj; }
const person = objectFactory(Person, 'hzzzzzzzq', 18); console.log(person.name); console.log(person.age); console.log(person.weight); person.getInfo();
|
发现,结果是一样的,这样就实现了吗?
当然不是,我们的构造函数如果有返回值呢?那会怎么样呢?
第二版 - 返回值
我们来看看例子,由此,我们可以看见,如果构造函数带有返回值,则会导致返回值以外定义的值无效。
- 如果是函数,则返回类型错误
- 如果是变量,返回 undefined
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function Person(name, age) { this.weight = 70;
return { name: name, age: age, }; } Person.prototype.getInfo = function () { console.log(this.name, this.age, this.weight); }; const person = new Person('hzzzzzzzq', 18); console.log(person.name); console.log(person.age); console.log(person.weight); person.getInfo();
|
但是返回值就一定是对象吗?结果显然是不一定。
所有,我们来看看不是对象时是什么情况:
1 2 3 4 5 6 7 8 9 10 11
| function Person(name, age) { this.name = name; this.age = age; this.weight = 70;
return 'hello'; } const person = new Person('hzzzzzzzq', 18); console.log(person.name); console.log(person.age); console.log(person.weight);
|
我们发现,都正确返回了,所以我们需要进行判断
- 构造函数返回的是一个对象,则返回这个对象
- 返回的是一个值,则忽略
接下来我们来更改我们的代码.
1 2 3 4 5 6 7 8
| function objectFactory() { const obj = {}; const Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; const result = Constructor.apply(obj, arguments);
return typeof result === 'object' ? result : obj; }
|
小结
我们来小结一下 new 做的事情。
- 创建一个空的简单
JavaScript
对象(即{}
)
- 为对象添加属性
__proto__
,将该属性链接至构造函数的原型对象
- 将该对象作为
this
的上下文 ;
- 如果该函数没有返回对象,则返回
this
。
到此,我们就完美复刻出了 new
操作喽。