js new 操作符做了什么

711 阅读2分钟

new 关键字会进行如下的操作:

  1. 创建一个空的简单JavaScript对象(即 {} );
  2. 为步骤1新创建的对象添加属性 proto ,将该属性链接至构造函数的原型对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

为什么要这么做呢? 无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个 constructor (构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(proto),指向构造函数的原型对象。

微信图片_20211116111138.png

上图展示了 Person 构造函数、Person 的原型属性以及 Person 现有的两个实例之间的关系。 在此,Person.prototype 指向了原型对象,而 Person.prototype.constructor 又指回了 Person。 原型对象中除了包含 constructor 属性之外,还包括后来添加的其他属性。Person 的每个实例—— person1 和 person2 都包含一个内部属性,该属性仅仅指向了 Person.prototype;换句话说,它们 与构造函数没有直接的关系。

用代码模拟实现:

function Mocknew() {

    var obj = new Object();
    
    //取出第一个参数,就是我们要传入的构造函数。shift 会修改原数组,所以 arguments 会被去除第一个参数
    Constructor = Array.prototype.shift.call(arguments);

    obj.__proto__ = Constructor.prototype;

    Constructor.apply(obj, arguments);

    return obj;

};

function Person(name, age){
    this.name = name;
    this.age = age
}

let p1 = Mocknew(Person,'zl',30)

注:为什么要用apply而不是bind呢,apply绑定this并执行该方法即构造函数,也就是让实例对象具有构造函数内的属性或方法,使用原型链的方式完美的实现了继承。当然,如果构造函数Person返回一个对象,那么在Mocknew方法内返回obj时需要判断一下,这里不做赘述,只是简单描述一下new的原理。