new

  1. 新生成了一个对象
  2. 链接到原型
  3. 绑定 this
  4. 返回新对象

在调用 new 的过程中会发生以上四件事情,我们也可以试着来自己实现一个 new

  1. function create() {
  2. // 创建一个空的对象
  3. let obj = new Object()
  4. // 获得构造函数
  5. let Con = [].shift.call(arguments)
  6. // 链接到原型
  7. obj.__proto__ = Con.prototype
  8. // 绑定 this,执行构造函数
  9. let result = Con.apply(obj, arguments)
  10. // 确保 new 出来的是个对象
  11. return typeof result === 'object' ? result : obj
  12. }

对于实例对象来说,都是通过 new 产生的,无论是 function Foo() 还是 let a = { b : 1 }

对于创建一个对象来说,更推荐使用字面量的方式创建对象(无论性能上还是可读性)。因为你使用 new Object() 的方式创建对象需要通过作用域链一层层找到 Object,但是你使用字面量的方式就没这个问题。

  1. function Foo() {}
  2. // function 就是个语法糖
  3. // 内部等同于 new Function()
  4. let a = { b: 1 }
  5. // 这个字面量内部也是使用了 new Object()

对于 new 来说,还需要注意下运算符优先级。

  1. function Foo() {
  2. return this;
  3. }
  4. Foo.getName = function () {
  5. console.log('1');
  6. };
  7. Foo.prototype.getName = function () {
  8. console.log('2');
  9. };
  10. new Foo.getName(); // -> 1
  11. new Foo().getName(); // -> 2

new - 图1

从上图可以看出,new Foo() 的优先级大于 new Foo ,所以对于上述代码来说可以这样划分执行顺序

  1. new (Foo.getName());
  2. (new Foo()).getName();

对于第一个函数来说,先执行了 Foo.getName() ,所以结果为 1;对于后者来说,先执行 new Foo() 产生了一个实例,然后通过原型链找到了 Foo 上的 getName 函数,所以结果为 2。