知识深度
大厂面试会通过各种难题来试探你的技术深度,评估你的技术发展潜力,这是入职后确定级别、薪资的重要参考。所以,技术深度将决定你的“钱途”。
为何要考察呢?
- 深挖你的技术“天花板”,看未来潜力和可培养性 —— 特别是对于刚毕业不就的新人。
- 如果面试通过了,大公司要定级(P6 还是 P7),其中技术深度就是很重要的参考标准。一个没有技术深度的人,不可能给高级别职称。
- 希望和有技术深度的工程师共事。而且,那么多候选人,择优录取,肯定希望能招募到技术深度好的工程师。
考察重点是我们日常使用的技术,的一些深入。没有什么特别出格的。
- 非应用层面,深入到原理层面
- JS相关原理
- Vue React 相关原理
技术深度,就有那么 1-2 个方面即可。深了,就不可能全面。技术深度的题目不过关,也不一定就面试不通过。
JS内存泄露如何检测?场景有哪些?
JS垃圾回收是指回收那些函数已经执行完成再也用不到的对象或数据,之前用的是引用计数,但是循环引用有缺陷,现在用的是标记清除,从js的根window向下遍历,找到就保留,找不到就清除。
内存泄露检测要看内存的变化,如果内存升高升高降下来,这是正常的情况,不算内存泄露。所以我们要看如何检测内存变化。内存变化可以使用chrome devtools中的Performance工具来进行检测。
内存泄露的场景(以Vue为例)
- 被全局变量、函数引用,组件销毁时未清除
<script>
export default{
data(){
return {
arr:[10,20,30]
}
},
mounted(){
window.arr = this.arr;
window.printArr = ()=>{
console.log(this.arr)
}
},
//Vue2
beforeUnmount(){
window.arr = null
window.printArr = null
}
}
</script>
- 被全局事件、定时器引用,组件销毁时未清除
<script>
export default{
data(){
return {
arr:[10,20,30],
intervalId: 0
}
},
mounted(){
this.intervalId = setInterval(()=>{
console.log(this.arr);
},100);
},
//Vue2
beforeUnmount(){
if(this.intervalId){
clearInterval(this.intervalId);
}
}
}
</script>
<script>
export default{
data(){
return {
arr:[10,20,30]
}
},
methods:{
printArr(){
console.log(this.arr)
}
},
mounted(){
window.addEventListener('resize',this.printArr);
},
//Vue2
beforeUnmount(){
window.removeEventListener('resize',this.printArr);
}
}
</script>
- 被自定义事件引用,组件销毁时未清除
<script>
export default{
data(){
return {
arr:[10,20,30]
}
},
methods:{
printArr(){
console.log(this.arr)
}
},
mounted(){
event.on('showMsg',this.printArr)
},
//Vue2
beforeUnmount(){
event.off('showMsg',this.printArr)
}
}
</script>
前几年前端不太注重内存泄露,因为不像后端7*24小时运行。近几年前端功能不断复杂,内存问题也要重点考虑。 那么闭包是内存泄露吗?
严格意义上来说闭包不算内存泄露,内存泄露是非预期的情况,想让它 回收但是它没回收。而闭包是符合预期的。
vdom真的很快吗?
vdom也就是Virtual DOM 虚拟dom,vue和react都使用vdom实现内部组件的更新,它是用JS对象来模拟DOM节点数据,由React最先推广使用。
Vue、React相比于jquery时代,它的价值是什么呢?
- 组件化,组件化在很早就有了,后端使用JSP、PHP的时候组件化就已经有了,包括后来有新的标准Web Components。所以组件化是承接之前技术的一个基本使用,它是一个必要条件
- 数据视图分离、数据驱动视图--这是核心,只关注业务数据,而不用关心DOM变化
现在很多初学的前端工程师,一上来使用Vue、React,对DOM操作不太熟练,慢慢变成了Vue工程师。
那么如何实现数据驱动视图呢?那就使用vdom
所以vdom并不快,JS直接操作DOM才是最快的。但数据驱动视图要有合适的技术方案,不能全部DOM重建,vdom就是目前最合适的技术方案(并不会因为它快,而是合适)
浏览器和nodejs事件循环的区别
JS是单线程的(无论是浏览器还是nodejs),浏览器中JS执行和DOM渲染共用一个线程,JS执行就暂停DOM渲染,因此异步就是解决这个问题而诞生,如果没有异步的话,同步执行JS就无法渲染DOM,渲染DOM就无法执行JS。
异步中又分为宏任务和微任务,宏任务就是常见的setTimeout、setInterval、网络请求,微任务就是promise、async/await。微任务在下一轮DOM渲染之前执行,宏任务在之后执行。因此微任务执行的更早一些,
Nodejs同样使用ES语法,也是单线程,也需要异步,异步任务也分宏任务和微任务。但是它的宏任务和微任务,分不同类型,有不同优先级。
console.log('start')
setImmediate(()=>{
console.log('setImmediate')
})
setTimeout(()=>{
console.log('timeout')
})
Promise.resolve().then(()=>{
console.log('promise then')
})
process.nextTick(()=>{
console.log('nextTick')
})
console.log('end')
//start
//end
//nextTick
//promise then
//timeout
//setImmediate
宏任务类型和优先级从高到低
- Timers - setTimeout setInterval
- I/O callbacks - 处理网络、流、TCP的错误回调
- Idle、prepare - 闲置状态(nodejs内部使用)
- Poll轮询 - 执行poll中的I/O队列
- Check检查 - 存储setImmediate回调
- Close callbacks - 关闭回调,如socket.on('close')
微任务类型和优先级
- 包括promise、async/await、process.nextTick,注意process.nextTick优先级最高
nodejs中event loop,先执行同步代码,然后执行微任务(process.nextTick优先级更高),按顺序执行6个类型的宏任务(每个结束时都执行当前的微任务)
所以浏览器和nodejs的event loop流程基本相同,nodejs宏任务和微任务分类型,有优先级。
越低级的代码,性能往往越好,用现成的api不知道其内部的复杂度。日常开发别只考虑性能,forEach代码可读性更好,前提是复杂度一致。
遍历数组,for和forEach哪个更快
for会更快,forEach每次都要创建一个函数来调用,而for不会创建函数,函数需要独立的作用域,会有额外的开销。
Vue每个生命周期都做了什么?
- beforeCreate:在创建之前,创建了一个空白的Vue实例,data、method尚未被初始化,不可使用,也就是这个阶段是一个空白的Vue项目而已,在beforeCreate里面做不了什么东西。
- created:这个时候Vue实例初始化完成了,也就是Vue的JS对象初始化完成了,然后响应式绑定完了。data、method都已经初始化完成,可以调用了。在created中与页面、DOM节点没有关系的东西和JS模型有关系的东西可以做了,比如获取一些属性,但是尚未开始渲染模板,Vue实例和模板还未发生关联,所以不要做与模板有关的事情。
- beforeMount:在渲染之前,编译模板,调用render生成vdom。还没有开始渲染DOM。
- mounted:完成DOM渲染,组件创建完成,开始由创建阶段进入运行阶段。
- beforeUpdate:data发生变化之后,准备更新DOM,但是尚未更新DOM。
- updated:data发生变化,DOM更新完成。注意不要在updated中修改data,可能会导致死循环。
- beforeUnmount:组件进入销毁阶段,尚未销毁,还可使用。可移除、解绑一些全局事件、自定义事件。
- unmounted:组件被销毁了,所有子组件也都被销毁了。
keep-alive组件有两个生命周期:onActivated缓存组件被激活,onDeactivated缓存组件被隐藏。
Vue什么时候操作DOM比较合适?mouted和updated都不能保证子组件全部挂载完成,所以要用$nextTick渲染DOM
Ajax应该放在哪个生命周期?有两个选择created和mounted,推荐mounted。
Vue3 Composition API生命周期有何区别?用setup代替了beforeCreate和created。使用Hooks函数的形式,如mounted改为onMounted()。
Vue2 Vue3 React的diff算法有何区别?
Tree diff的优化:只比较同一层级,不跨级比较。tag不同则删掉重建,不再去比较内部的细节。子节点通过key区分(key的重要性),for循环要有Key,这个key深入到diff算法的优化。优化后的时间复杂度为O(n)。
diff算法非常复杂,不要深究细节。既然是三者的比较,说出他们最大的不同即可。
React diif仅右移,Vue2双端比较,Vue3最长递增子序列。
Vue React为何循环时必须使用key,vdom diff算法会根据key判断元素是否要删除,匹配了key,则只移动元素性能较好。未匹配key,则删除重建性能较差。
Vue-router的MemoryHistory是什么?
MemoryHistory是适用于Vue3的vue-router,在Vue2中vue-router的abstract模式。
Vue-router三种模式主要是Hash、WebHistory、MemoryHistory(V4之前叫做abstract history)
React-router也有和Vue-router相同的三种模式。
知识深度很重要
虽然我们日常干的都是“拧螺丝”“搬砖”的 CURD 工作,也体现不出什么难度,但自身的知识深度真的很重要。工作是公司的、老板的,而能力是自己的,要区分开来。
面试评级
面试通过了,到底给你评定 P6 还是 P7 ?依据什么标准呢?
- 第一个因素不是你的技术,而是团队的预算,例如他们还有没有 P7 的名额。如果有,那可以考虑;如果没有,你能力再好也大不了 P7 。说这个因素是告诉你:如果你的平级不高,不一定是个人的因素。
- 第二个因素就是你的综合技术能力,而其中技术深度就是最关键的一个。如果你只是浮于表面,从未深入到原理或者源码层面,那就很难有说服力。
- 大厂不同级别的工资是不一样的,所以技术深度直接决定了你的“钱途”。
难题攻坚
在实际工作中,项目遇到了难题,老板可能会直接指派给你,也可能开会时叫人主动认领(此时你要量力而行,不要随意“抢答”)。无论何种方式,你接到了这样一个难题,是否能解决将决定你在领导心目中的形象。
最后,要解决难题,最需要的就是技术深度。否则你都看不清楚问题的本质,何谈解决?
同事之间的影响力
同事之间除了聊工作,还有很多私下随性沟通的机会,特别是午饭、午休时间。聊技术,永远是技术人员的话题。
在聊天过程中,大家都会发表个人的评论和观点。如果你有技术深度,看问题更加透彻,解释问题更加清晰,在同事眼中你自然就是一个“厉害的人”。
得到同事的认可和尊重,会增加工作的幸福感。人都有本能的社交需求。
注意
所谓技术深度,深了就不可能广。所以,找准某一个方面深入进去即可,不可贪多。而且,要找一个主流的技术栈,如 Vue React 相关的,要考虑技术的实际价值。