JavaScript 的 new 运算符

JavaScript 的 new 运算符
0

new 运算符是 JavaScript 实现面向对象的一个重要的运算符,用于创建某种类型(包括自定义类型和内置类型)的一个实例(instance)。

例如 new Object() 创建一个 Object 的实例,new String("abc") 创建一个 String 的实例。

但是 JavaScript 与一般的基于类的面向对象编程语言不同,它是基于原型链的。那么 new 运算符与原型链有什么关系呢?可不可以不用 new 运算符来实现 new 运算符的功能呢?

事实上,JavaScript 中不需要 new 运算符仍能实现 new 运算符的功能。

根据 ECMAScript 规范中对 new 运算符的定义以及 MDN 中对 new 运算符的描述,使用了 new 运算符的语句 var a = new A() 实际上相当于如下 JavaScript 代码:

var a;
(function () {
    // 1、确保 A 是一个 constructor
    if (typeof A !== 'function') {
        throw new TypeError("A is not a constructor");
    }
    // 2、创建一个空对象
    var temp = {};
    // 3、以该对象作为 this 调用 constructor
    // 若 constructor 有返回值,则将该返回值作为 new 表达式的值
    a = A.call(temp);
    // 4、若 constructor 没有返回值,则将第 2 步创建的对象作为 new 表达式的值
    if (typeof a === 'undefined') {
        a = temp;
    }
    // 5、设置对象的原型对象
    Object.setPrototypeOf(a, A.prototype);
})();

使用了 new 运算符的语句 var b = new B(param1, param2, param3) 实际上相当于如下 JavaScript 代码:

var b;
(function () {
    // 1、确保 B 是一个 constructor
    if (typeof B !== 'function') {
        throw new TypeError("B is not a constructor");
    }
    // 2、创建一个空对象
    var temp = {};
    // 3、以该对象作为 this,以 new 表达式中 constructor 的参数作为参数调用 constructor
    // 若 constructor 有返回值,则将该返回值作为 new 表达式的值
    b = B.call(temp, param1, param2, param3);
    // 4、若 constructor 没有返回值,则将第 2 步创建的对象作为 new 表达式的值
    if (typeof b === 'undefined') {
        b = temp;
    }
    // 5、设置对象的原型对象
    Object.setPrototypeOf(b, B.prototype);
})();

在实现 ECMAScript 5.1 版本之前,这是 JavaScript 中唯一可以规范地指定一个对象的原型([[prototype]] 内部属性)的方法(__proto__ 属性并不是规范的方法,旧版本的 JavaScript 没有 Object.createObject.setPrototypeOf 方法)。因此在 ECMAScript 5.1 版本之前,使用 new 运算符是 JavaScript 实现面向对象编程的唯一方式。