# 手写new关键字
new包括四个阶段- 创建一个新对象
 - 这个新对象的
__proto__属性指向原函数的prototype属性。(即继承原函数的原型) - 将这个新对象绑定到 此函数的 
this上 。 - 返回新对象,如果这个函数没有返回其他对象。
 
// 1、Con: 接收一个构造函数
// 2、args:传入构造函数的参数 
function create(Con, ...args){
    // 创建空对象
    let obj = {};
    // 设置空对象的原型(链接对象的原型)
    obj._proto_ = Con.prototype;
    // 绑定 this 并执行构造函数(为对象设置属性)
    let result = Con.apply(obj,args)
    // 如果 result 没有其他选择的对象,就返回 obj 对象 
    return (typeof result === 'object') && result != null ? result : obj;
}
// 构造函数
function Test(name, age) {
    this.name = name
    this.age = age
}
Test.prototype.sayName = function () {
    console.log(this.name)
}
// 实现一个 new 操作符
const a = create(Test,'linjiaheng','22') 
console.log(a.age)
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
通过现代浏览器的操作属性的便利性,可以改变一个对象的
[[Prototype]]属性, 这种行为在每一个JavaScript引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在obj.__proto__ = ...语句上, 它还会影响到所有继承来自该[[Prototype]]的对象,如果你关心性能,你就不应该在一个对象中修改它的[[Prototype]]。相反, 创建一个新的且可以继承[[Prototype]]的对象,推荐使用Object.create()
function create(Con, ...args){
    // 创建空对象
    let obj = {};
    // 设置空对象的原型(链接对象的原型)
    obj = Object.create(Con.prototype);
    // 绑定 this 并执行构造函数(为对象设置属性)
    let result = Con.apply(obj,args)
    // 如果 result 没有其他选择的对象,就返回 obj 对象 
    return (typeof result === 'object') && result != null ? result : obj;
}
 1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
TIP
构造函数执行,不写 return,浏览器会默认返回创建的实例,但是如果我们自己写了return。
- 基本值:
return是一个基本值,返回的结果依然是类的实例,没有收到影响。 - 引用值:如果返回的是一个对象,则将默认的返回的实例覆盖,接收的结果就不再是当前类的实例。