# 实现new

考点:

  • 构造函数, 原型链

函数通过 new 操作符调用, 此时函数被称为构造函数, 运行后会返回一个对象, 该对象的 __proto__ 属性指向构造函数.prototype

    function Cat(name) {
      this.name = name;
    }
    Cat.prototype.miao = function () {
      console.log("瞄~!");
    };
    let cat = new Cat("大毛");
    console.log(cat.__proto__ == Cat.prototype); // true
1
2
3
4
5
6
7
8

由于 new 是语言层面的操作符, 所以用函数来模拟 new的功能:

    function newFactory(constructor) {
      let obj = Object.create(constructor.prototype) 
      // 等同于  obj.__proto__ = constructor.prototype

      let args = Array.from(arguments).slice(1)
      constructor.apply(obj, args)
      return obj
    }

    function Cat(name, color) {
      this.name = name;
      this.color = color
    }
    Cat.prototype.miao = function () {
      console.log("瞄~!");
    };
    let cat = newFactory(Cat,"大毛", '橘色');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

改进: 当构造函数本身会返回一个非null的对象时, 则通过 new 会返回这个对象, 其他情况还是会返回新生成的对象

    function Cat(name) {
      this.name = name
      return {
        name: 'zs'
      }
    }
    Cat.prototype.miao = function() {
      console.log('瞄~!')
    }
    let cat = new Cat('大毛')
    console.log(cat.name)  // 'zs'
1
2
3
4
5
6
7
8
9
10
11

因此需要将调用 cat后返回的结果进行判断, 如果是非null的对象, 则返回该对象, 其他情况返回新生成的对象

      function newFactory(constructor) {
        let obj = Object.create(constructor.prototype);
        // 等同于  obj.__proto__ = constructor.prototype

        let args = Array.from(arguments).slice(1);
        let result = constructor.apply(obj, args);
        return result instanceof Object ? result : obj
      }

      function Cat(name, color) {
        this.name = name;
        this.color = color;
        return {
          name: 'zs'
        }
      }
      Cat.prototype.miao = function () {
        console.log("瞄~!");
      };
      let cat = newFactory(Cat, "大毛", "橘色");
      console.log(cat)  // {name:'zs'}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
上次更新: 2020/11/24 下午2:27:13