解析与实现 new 运算符

tip:先弄懂原型和原型链再看new的实现

new 的实现流程

  1. 生成一个新对象
  2. 链接对象,将新创建的对象__proto__指向到对应原型对象上
  3. 将上下文,设置为新建对象的指针(this)
  4. 如果构造函数没有返回对象类型,则返回新建的对象。

流程解析:

  1. 为什么要生成一个新对象?
    • 新的实例,需要新的内存引用
    • 因为任意对象都有属性__proto__
  2. 为什么要将__proto__指向原型对象?
    • 在调用对象属性时,如果当前对象没有这个属性,会从__proto__中寻找,因为__proto__指向原型对象,相当于复用原型对象的方法。
    • 符合原型链规则,因为js底层设计如此,最终指向都是null。
  3. 为什么要将上下文,设置为新建对象的指针(this)?
    • 构造函数初始化,会形成新的引用,确保形成完整的原型链。
  4. 为什么如果构造函数没有返回对象类型,则返回新建的对象?
    • new 结果必须返回一个对象引用,如果构造函数没有返回对象,我们也不返回新建对象的话,那么会导致new的结果指向undefined,javascript是不运行undefined设置属性,最终导致调用方错误异常。

完整实现

/**
 * @description new 的实现
 * @param {Function} ctor [构造函数]
 * @return {Object|Function|Regex|Date|Error} [结果]
 */
function fakeNew (ctor) {
  // 加一下类型保护,确保构造函数是函数
  if (typeof ctor !== 'function') {
    throw   'Are you kidding me?It need constructor' 
  }
  
  // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target
  // ES6 规定 new.target 指向构造函数,是为了入开发者检测是否是new实例化的。
  fakeNew.target = ctor;
  
  // 1.创建一个新对象
  // 2.顺便将__proto__指向到构造函数的prototype
  var newObj = Object.create(ctor.protoType);
  
  // 因为构造函数有初始化的行为,所以获取剔除构造函数余下的参数传入构造函数
  var args = [].slice.call(arguments, 1);
  // 执行构造函数
  var res = ctor.apply(newObj, args);
  
  var isObj = res === null || typeof res === 'Object';
  var isFn = typeof res === 'function';
  if(isObj || isFn) {
    return res;
  }
  // 构造函数没有返回对象,则返回新建对象
  return newObj;
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享