主要使用的技术栈是vue,所以刻意避开了react,写在这里也是为了给自己总结多看看,兄弟们如果有什么补充或修改的内容可以直接发给我,感谢各位大哥,因为是面试时讲的,所以代码部分就很少了,而且不太会写文章格式,各位见谅
一、vue2和vue3的区别
1、vue2主要使用的是js,vue3主要使用的是ts
2、vue2的生命周期有11个,vue3的生命周期有12个,而且vue3的生命周期是api内部传入回调函数所以可以重新使用多次
3、vue2和vue3使用的技术栈会有所不同,比如vue2用vue-router3,vue3则使用vue-router4,还有element组件库不同
4、vue3中增加了Teleport瞬移组件,还有一个suspense占位具有加载效果组件
5、vue3支持vue2的大部分特性;vue3使用的是组合式api,vue2是选项式api;vue2中组件要有根标签,vue3中没有这个限制;vue3中一般没有this,也就避免了对于this指向不清的问题
6、也可以聊响应式原理的区别,但一定要自己熟悉,使用了proxy代替defineProperty来实现数据响应式
二、如何防抖和节流
当这个事件触发时,给定一个定时器做延迟触发,防抖需要做的事情是每次点击时,清除并重置定时器,只会在最后一次点击的n秒之后执行业务,实现多次点击变一次;节流需要额外设置一个标记变量,在定时器等待时直接return当前事件,之后定时器进入执行且标记变量取反,在定时器执行结束后会把标记变量重置,实现多次点击变少次
三、什么是闭包
闭包是一个函数及其捆绑的周边环境状态的引用的组合,函数之间有嵌套,且内部函数用到了外部函数的变量,在外部函数调用,此时就形成闭包,闭包就是用来延长局部变量的生命周期,将局部变量的数据缓存下来让函数外部可以获取到,这也导致了本该销毁的数据依旧存活,数据量大的话就会出现内存的泄漏,最终导致内存溢出
四、双向绑定使用和原理
最常见的就是v-model双向数据绑定了,在模板解析的时候,获取文本框节点,遍历里面的属性,找到v-model属性属于普通指令,调用compileUtil属性的model方法,内部通过bind方法调用updater对象中的方法,为文本框的vaule属性赋值,同时建立dep和watcher对象的关系,最终使用addEventListener绑定input事件及对应回调函数,当文本框的值发生改变,就会触发input事件,通过事件源对象获取改变后的新值,然后修改data中的属性值,会触发数据代理和数据劫持中的set方法,内部通过修改属性对应的dep对象调用notify方法通知关联的watcher调用run方法,对界面进行渲染
模板解析、数据代理及数据劫持可以看一下源码进行分析会较为清晰
五、ES6新增特性(常用语法)
es6是2015年发布的,全称ECMA2015,到2023年已经到了es14,es6以后一年更新一个版本,es6新增了一些特性:
1、let、const用来声明变量和常量,也就意味着出现了块级作用域,let和const的声明的变量和常数是有提升的,根据官方文档可知,虽然提升但是不能使用
2、解构赋值运算符...
3、class,用来定义类,可以使用extend和super继承
4、导入导出export import模块化相关的关键字
5、symbol数据类型,用来定义唯一的数据标识
6、数组对象字符串都增加了扩展的相关方法
7、iterator接口机制,也就是迭代器
8、generator函数用来实现异步操作;新增了promise和async、await
9、set、map容器,set可以创建一个无序不重复的元素集合,map以键值对的方式存储数据
10、proxy对象,可以用来实现数据的代理和响应式
11、箭头函数以及模板字符串
六、表单数据在一个视图对象里,如果变更表单数据但视图对象未改变,如何处理
可在数据变化之后立即使用 Vue.nextTick,这样回调函数在 DOM 更新完成后就会调用。
// 因为这个提到了nextTick,所以面试官大概率还会接着往下问
nextTick在下次dom更新循环结束之后,执行延迟回调,应该是在数据更新之后立刻调用这个方法,获取更新后的dom,当这个方法执行的时候会传入回调,内部有一个callbacks数组用来存储传入的回调,以及更新界面的回调,如果在更新数据后使用nextTick方法,内部会先把更新界面watcher对象对应的回调先加入到callbacks数组中,通过定时器的方式把手动传入的回调变成宏任务,这样就做到了先更新数据再更新界面再执行传入的宏任务回调,如果是先调用nextTick方法后更新数据,那么内部callbacks数组中手动传入的回调会通过promise或者mutationobserver变成微任务,更新界面watcher对应的回调后执行,那么这个执行流程就是,更新数据,执行微任务,再更新界面
这里可以再聊聊js的事件轮循机制
七、数组中的方法
会改变原数组的:pop、push、shift、unshift、revserse、sort、splice
不会改变原数组的:concat、join、slice、filter、reduce、find、findIndex
具体用法可以看看文档,一般会用在场景题里
八、对虚拟长列表有了解吗
虚拟长列表其实也可以归结为按需显示,只会对可见区域渲染,常用的场景是,当前页面中有大量但是又不能分页展示的列表数据,并让其可以达到在页面中自动滚动展示固定条数,同时又要求性能
思路是首次渲染时,先加载我们可见的最大条数,再分析滚动时的情况,动态通过计算滚动值得到此时在屏幕中应该展示的数据,并且要将上面滚动过的列表数据删除,需要计算的数据会比较多
为了使页面滚动更为平滑,可以在可见区域上下预先缓存一些数据
九、组件的通信方式
说大概五六个熟悉的就可以
props 用来实现父子 子父组件通信
自定义事件 用来实现父子组件通信
全局事件总线 任意组件通信,原理是在vue的原型对象上绑定一个vue的实例,各个组件的实例对象与它是继承关系,原型对象上可以绑定一个$api存储所有接口函数
插槽 可以占位,实现父子 子父组件通信 普通、具名、作用域插槽
provide inject 可以实现直接或间接的父子 / 子父组件通信
pubsub 不属于任何框架 独立存在 可以实现任意页面的组件通信
vuex 集中式状态管理工具,可以实现任意组件之间的通信,里面有五个对象:
states 包含了多个状态数据的对象
mutation 包含了多个直接修改状态数据的方法的对象
actions 包含了多个间接修改状态数据的方法的对象
getters 包含了多个状态数据的计算属性的get方法的对象
modules 包含了多个子级模块的对象
数据修改的方式为组件中分发action,action内部对应的mutation进行数据修改,或者组件中直接commit对应mutation,总的action和子的action如果同名,先执行总的再执行子的,mutation中可以进行异步操作但是不推荐,因为浏览器的vue调试插件中不能够及时更新数据,有可能导致页面不能及时更新
pinia 更加适配vue3的轻量级状态管理库,有着更完整的TypeScript支持,比起vuex少了mutation和modeules,这是因为async和await的出现使异步任务变得可控,pinia更为轻量,且可以创建多个仓库,上手较为容易;pinia近些年的发展也逐渐赶上了vuex
十、项目做过哪些优化
可以结合实际项目讲
最常见的就是第三方插件按需引入;路由进行懒加载;高频事件用节流进行优化;大量事件绑定可以使用事件委派进行优化;大量数据渲染可以进行分页或虚拟长列表进行优化;v-show和v-if控制页面显示隐藏,根据两者特性,触发频繁就使用v-show,不频繁就使用v-if
配置webpack的splitChunk进行代码分割将组件库单独进行打包;tree Shaking剔除多余的代码让代码体积更小
开启gzip进行文件的压缩设置;开启浏览器的缓存机制;设置http协议版本
当然还有很多很多题,很细很小,主要还是要看公司的,很多都是只问项目,会问得比较深,所以一定要对自己项目了解很透彻。
留个小尾巴:深浅拷贝、css垂直水平居中、两栏布局、隐藏元素、深度选择器、屏幕自适应适配、路由守卫、原型、diff算法、cookie的携带