“我报名参加金石计划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:写的挺不错的嘛,逻辑也挺清晰的;好,这一块过了,下一个问题是,请说说...