你真的懂new操作符吗

96 阅读3分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

不会弹吉他的铁匠不是一名好铁匠!大家好,我是拿吉他的铁匠,码字不易,希望大家多多点赞。

书接上回,铁匠来到公司面试,面试官提出的第一个问题是防抖和节流,铁匠回答的行云流水;下面面试继续:

面试官大A:请说一下 new 操作符做了哪些事情吧? 铁匠:心中暗喜,new 操作符那不是嘎嘎熟悉。

是什么?

关于new 操作符,我相信大家并不陌生,我们在接触构造函数或者类的时候,都会使用new构造实例;那么问题来了,new是如何构造出实例对象,过程又是怎样的?

new操作符做了哪些事情?

  • 创建一个空的对象;
  • 设置原型链,将空对象的隐式原型__proto__指向构造函数的原型对象;
  • 改变this指向,将构造函数里面的this指向空对象并执行函数体;
  • 判断构造函数返回值类型;

你也许会好奇,为什么最后一步要判断构造函数返回值的类型;构造函数一般是没有返回值的,但是构造函数也是函数,也是可以return数据的;正是这一点,new操作符最后要进行一次值的判断;通过案例会更加清晰:

function SimpleData (name) {
  this.name = name
  return 'aa'
}
let s1 = new SimpleData('hello')
console.log(s1) // {name: 'hello'}
function ComplexData (name) {
  this.name = name
  return { msg: '不是new出来的实例' }
}

let c1 = new ComplexData('world')
console.log(c1)  // {msg: '不是new出来的实例'}
  • 通过这两个小小的案例,相信对new操作符为啥要对构造函数的返回值进行判断会有更加清晰地了解;所以会得出以下地结论:

    • 如果return简单数据类型,那么忽略该返回值,即效果和没有返回值一样;
    • 如果return引用数据类型,那么最后返回的结果是return后面的数据,而不是new出来的实例,即new操作符失效;

面试官大A: 理论了解的挺透彻的,在这张纸上模拟一下new的实现吧;

铁匠:又到了手写代码的时刻了,那我就简单露一手吧;

模拟实现

模拟new操作符的实现,其实也就是用代码实现new操作符做的每一步;

function myNew (Func, ...args) {
  // 创建一个空对象
  let obj = {}
  // 设置原型链
  Object.setPrototypeOf(obj, Func.prototype)
  // 改变this指向,并获取构造函数的返回值
  let result = Func.apply(obj, args)
  // 判断构造函数的返回值进而决定new操作符的返回值
  return result instanceof Object ? result : obj
}

测试

// 简单数据类型
function SimpleData (name) {
  this.name = name
  return 'aa'
}
let s2 = myNew(SimpleData, 'simpleDemo')
console.log(s2) // {name: 'simpleDemo'}
// 引用数据类型
function ComplexData (name) {
  this.name = name
  return { msg: '不是new出来的实例' }
}
let c2 = myNew(ComplexData, 'complexDemo')
console.log(c2)  // {msg: '不是new出来的实例'}

面试官大A:写的挺不错的嘛,逻辑也挺清晰的;好,这一块过了,下一个问题是,请说说...