模拟实现JS中new操作符的工作原理


面试中,有些面试官通常会问: new一个的过程发生了什么?

今天我们就来探索一下,并手动模拟一下new操作符的工作原理;

首先我们来看一下原生new的用法:

function Person(name,age){
    
    
  this.name = name
  this.age = age
}
Person.prototype.hobbit = "听音乐"

var XH = new Person('小红','20')

console.log('new--',XH.name) // new-- 小红
console.log('new--',XH.age) // new-- 20
console.log('new--',XH.hobbit) // new-- 听音乐

官方定义

官方文档对new的定义和描述如下:

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

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

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

说白点,就算不看官方文档,我们根据上面new实现的代码,也可以发现:

  • new一个函数会返回一个实例对象
  • 在执行构造函数的过程中,会给返回的实例对象自身添加一些属性
  • 并且实例对象还会继承构造函数原型上的一些属性和方法

模拟实现new工作原理

既然我们知道了new的工作流程,那我们就自己学一个函数来模拟new的工作原理:

function myNew(){
    
    
 //第一步:创建一个空对象
  const obj = new Object()
 //第二步:相当于 const restArgs = arguments.shift(1)
 //shift()修改原数组,把数组的第一个元素从其中删除,并返回第一个元素的值。
 //restArg就是构造函数(Constructor),arguments就是删除第一个构造函数外的参数集合
  const restArg = [].shift.call(arguments, 1)
 //第三步:obj继承构造函数原型上的属性和方法
  obj.__proto__ = restArg.prototype;
 //第四步:obj继承构造函数的属性和方法
  restArg.apply(obj, arguments)
 //第五步:返回对象
  return obj
}

myNew()最后返回的对象既可以访问到构造函数里的属性,又可以访问到构造函数原型中的属性 ,基本实现了new功能;

下面我们就来验证一下:

 var XH1 = new myNew(Person,'小红','20')

 console.log('myNew--',XH1.name) // myNew-- 小红
 console.log('myNew--',XH1.age) // myNew-- 20
 console.log('myNew--',XH1.hobbit) // myNew-- 听音乐

下面是代码实现图片:(有图有真相)

在这里插入图片描述

构造函数有返回值

上面为什么说基本实现了,其实new还有一个特性:

  • 如果构造函数又返回值,返回一个对象时,在实例 对象中只能访问返回的对象中的属性。
  • 返回一个基本类型的值时,等于是没有返回,new 实例正常访问属性

代码如下:

function Person(name,age){
    
    
  this.name = name
  return {
    
    
      age:20
  }
}

var XH = new Person('小红)

console.log(XH.name); // undefined
console.log(XH.age); // 20
console.log(XH.__proto__ === Object.prototype); // true
console.log(XH.__proto__ === Person.prototype); // false

new模拟实现的最终版

function myNew(){
    
    
 //前面四步都不变
  const obj = new Object()
  const restArg = [].shift.call(arguments, 1)
  obj.__proto__ = restArg.prototype;
  let ret = restArg.apply(obj, arguments)
 //第五步:判断返回类型,如果是一个对象,我们就返回这个对象,否则返回实例对象
  return typeof ret === 'object' ? ret : obj
}

猜你喜欢

转载自blog.csdn.net/qq_44182284/article/details/121854392