new运算符解析

new运算符创建一个用户定义的对象类型的示例或具有构造函数的内置对象示例。在调用new运算符的过程中,会进行如下的操作。

  • 创建一个简单的空的对象
  • 链接该对象到另一个对象
  • 对空对象绑定this
  • 返回新对象
    示例如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function Car(brand, model, year) {
    this.brand = brand;
    this.model = model;
    this.year = year;
    }

    Car.prototype.wheel = 4;

    Car.prototype.info = function() {
    return 'brand:' + this.brand + ', model:' + this.model + ', year:' + this.year;
    }

    var benz = new Car('Mercedes', 'glc', 2019);
    console.log(benz.wheel);
    console.log(benz.info());

从这个例子可以看出,实例benz

  • 可以访问到Car构造函数的属性
  • 可以访问到Car.prototype中的属性

那么,如何模式new关键字的,我们用objectFactory来模拟new的效果,大致如下:

1
2
function Car() {};
var benz = objectFactory(Car, ......);

初步尝试

回顾调用new的4步操作,创建一个空对象,链接空对象到另外一个对象,绑定this,最后返回对象。那么,我们也需要创建一个空对象对返回,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
function objectFactory() {
// 创建空对象
var obj = {};
//
var Constructor = [].shift.call(arguments);
// 链接空对象到另外一个对象
obj.__proto__ = Constructor.prototype;
// 绑定this
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
23
24
25
26
27
function objectFactory() {
// 创建空对象
var obj = {};
//
var Constructor = [].shift.call(arguments);
// 链接空对象到另外一个对象
obj.__proto__ = Constructor.prototype;
// 绑定this
Constructor.apply(obj, arguments);
// 返回
return obj;
}
function Car(brand, model, year) {
this.brand = brand;
this.model = model;
this.year = year;
}

Car.prototype.wheel = 4;

Car.prototype.info = function() {
return 'brand:' + this.brand + ', model:' + this.model + ', year:' + this.year;
}

var benz = objectFactory(Car, 'Mercedes', 'glc', 2019);
console.log(benz.wheel);
console.log(benz.info());

有返回值的情况

上面的样例是没有返回值的情况,有返回值的情况该如何处理呢?举例说明,同样是第一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Car(brand, model, year) {
this.brand = brand;
this.model = model;
this.year = year;
return {
model: model,
year: year
};
}

Car.prototype.wheel = 4;

Car.prototype.info = function() {
return 'brand:' + this.brand + ', model:' + this.model + ', year:' + this.year;
}

var benz = new Car('Mercedes', 'glc', 2019);
console.log(benz.wheel) // undefined
console.log(benz.info()) // Uncaught TypeError: benz.info is not a function
console.log(benz.model) // glc

在这段代码中,Car构造函数返回了一个对象,在实例benz中中能访问返回的对象中的属性。还有一种特殊情况,我们返回的是一个对象,假设返回的是一个基本类型呢?所以我们需要判断返回值的类型,优化后的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
function objectFactory() {
// 创建空对象
var obj = {};
//
var Constructor = [].shift.call(arguments);
// 链接空对象到另外一个对象
obj.__proto__ = Constructor.prototype;
// 绑定this
var res = Constructor.apply(obj, arguments);
// 返回
return typeof res === 'object' ? res : obj;
}