手撸一个new

new 做了什么事情

我们从栗子开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// react
const Dog = function(name) {
  this.name = name;
};
Dog.prototype.bark = function() {
  console.log("wangwang");
};
Dog.prototype.sayName = function() {
  console.log("my name is " + this.name);
};
const wang = new Dog("");
console.log(wang);
wang.bark();
wang.sayName();

结果: 那么,new究竟做了什么呢?

  1. 创建了一个新对象(是 Object 类型的数据)
  2. 将 this 指向新对象
  3. 将创建的对象的原型指向构造函数的原型
  4. 返回一个对象(如果构造函数本身有返回值且是对象类型,就返回本身的返回值,如果没有才返回新对象)

手动实现一个 new

废话不说,直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// react
_new(fn, ...arg) {
    // 1.创建了一个新对象
    const obj = {}
    // 2.将 this 指向新对象
    const ret = fn.apply(obj, arg); // 通过apply将this指向由Fn变为obj
    // 3.将创建的对象的原型指向构造函数的原型
    obj.__proto__ = fn.prototype
    // 1 3 可以合并为const obj = Object.create(fn.prototype);
    // 4. 返回一个对象
    return ret instanceof Object ? ret : obj;
  }
/////////////////
const miao = this._new(Dog, "");
console.log(miao);
miao.bark();
miao.sayName();

结果:

关于为什么要判断 ret instanceof Object

instanceof Object 来判断是否是对象,包含 Array,Object,Function、RegExp、Date,具体类型判断可以看我上一篇博客 判断数组(判断类型) 扶正,构造函数是能够自己指定返回一个对象的,so,如果不判断类型,_new出来的对象可能就不对了,栗子说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
////// 修改Dog
const Dog = function(name) {
  this.name = name;
  return {
      a: '嗬嗬'
  }
};
//////
_new(fn, ...arg) {
    const obj = Object.create(fn.prototype);
    const ret = fn.apply(obj, arg);
    return obj
  }
  ////////
const wang = new Dog("");
console.log(wang);
wang.bark();
wang.sayName();
const miao = this._new(Dog, "");
console.log(miao);
miao.bark();
miao.sayName();

结果1,原生new: 结果2,_new: 可以看到,原生的new因为Dog构造函数只return了 {a:嗬嗬},所以报错了,而没有判断类型的_new没有返回{a:'嗬嗬'}