朴实无华实现new运算符

100 阅读3分钟

最近很多兄弟面试的时候都遇到实现new运算符的问题,这篇我们就来谈谈new操作符。

1、什么是new运算符

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。简而言之,就是就一个构造函数或者class创建一个实例。

2、实现过程

实现过程千奇百怪,但是步骤都是殊途同归,读者想怎么写就怎么写,一共可分为四个步骤

第一步:创建一个对象并且返回这个对象

大家回想下new一个构造函数,打印下返回值看看是不是一个对象。

function newFn(){
  let obj = {};
  return obj;
}

第二步:改变这个对象的原型

因为后续要调用这个构造函数的方法,总不能把方法一个个赋值给这个对象,所以就想到了原型,只要把创建对象的原型指向构造函数的原型,就能继承构造函数的方法了。首先要接收构造函数Fn,有三种方式,一种直接赋值,一种是Object.setPrototypeOf(),还有一种是使用Object.create(Fun.prototype)

方法一

function newFn(Fn){
  let obj = {};
  obj._proto_ = Fn.prototype
  return obj;
}

方法二

function newFn(Fn){
  let obj = {};
  Object.setPrototypeOf(obj, Fn.prototype);
  return obj;
}

方法三

//这个方法较为精简,把第一步和第二步合在一起
function newFn(Fn){
  let obj = Object.create(obj, Fn.prototype);
  return obj;
}

第三步:改变对象的this指向

到了第二步,已经可以使用构造函数的方法了,但此时的this指向不是指向第一步已经创建的对象,改变this指向,并且立即执行有两个方法,applycall,这两个都无伤大雅,都可以实现我们想要的效果,只不过是传入的参数是不是以数组的形式。这一步需要我们传入函数的参数...args

function newFn(Fn,...args) {
  let obj = Object.create(obj, Fn.prototype);
  let result = Fn.call(obj, ...args); 
  //apply的方式
  //let result = Fn.apply(obj, args); 
  return obj;
}

看到这步,有人就会感到奇怪了,怎么多了result,这个result有啥用呢,第四步的时候会用到这个

第四步:判断返回值

在 JavaScript 中,构造函数可以返回一个对象,也可以返回其他类型的值。如果构造函数返回一个对象,那么该对象将作为 new 操作符的结果返回,而不是新创建的对象 obj。因此,我们需要判断 result 的类型,如果是对象,则将其作为结果返回,否则返回新创建的对象 obj

function newFn(Fn,...args) {
  let obj = Object.create(obj, Fn.prototype);
  let result = Fn.call(obj, ...args); 
  return typeof result === "object" ? result : obj;
}

至此,完成了new的实现,这个题目并不难,主要在于new操作符实例化一个构造函数的每一个步骤,分解开来,编程重在逻辑,只要明白了其中的逻辑,我们不需要背面试题,就能轻松写出这个问题的答案