20251224/20251225-记录总结

27 阅读10分钟

1. vue3和vue2的区别和底层原理?

(1.1) vue2是选项式Api,vue3是组合式Api

  • vue2按照data,methods,computed分布,逻辑分散,代码复用困难,同时代码是耦合的,在实现按需引入上比较困难,性能体现上明显不如vue3
  • vue3按照业务逻辑组织代码,引入代码钩子函数,支持逻辑复用,支持按需引入,支持TreeShaking,首屏开启的性能上有明显优势

(1.2) 关键核心区别是底层原理不一样:

  • vue2依托于Object.defineProperty,会在创建的时候给每个属性建立getter和setter,通过发布订阅的模式来实现响应式,缺点是无法监听新增 / 删除属性
  • vue3依托于es6的Proxy和Reflect,代理劫持整个对象,能够实现对于新增/删除属性,不需要额外的set函数

(1.3) Diff算法不一致

  • vue2全量对比,无差别对比,无论数据是否是响应式都会无差别对比是否发生更新
  • vue3精准对比,在第一次渲染的时候,会把响应式数据打上PatchFlags标签,然后把非响应式数据静态提升到渲染函数外面,后续按照被标记为PatchFlags的节点按需更新,静态数据直接复用,大量节省对比的开销

2. v-for中key的作用?

  • Diff算法中用于识别更新对象,方便vue快速定位到对应的变更节点,不然就不得不全量遍历所有被标记为PatchFlags标签的对象,用于提升,特别是针对大数据渲染的场景,提升vue的渲染效率;

比如一个列表展示,最上面是一个输入框用于展示点击的列表节点的标签名字,如果中途进行列表的反转,没有Key进行列表的唯一标识符,则会出现输入框信息错位的场景

  • 同时如果key用错,比如重复给不同的节点使用相同的key,会导致Dom渲染混乱

3. Map和Set的区别?WeakMap和WeakSet的区别?

WeakMap 和 WeakSet 都是「强引用」集合,可以被遍历

  • Map:Key-Value结构,存键值对集合
  • Set:value,存唯一的数据,唯一集合,可以用来处理数组数据的去重

WeakMap 和 WeakSet 都是「弱引用」集合,不可以被遍历,核心设计目标是不阻止垃圾回收(GC) ,避免内存泄漏

  • WeakMap:Key-value结构,key是弱引用,value是强引用,key的元素必须是对象

Vue3高性能的原因之一就是使用WeakMap去存储响应式对象关联的依赖,把响应式对象作为键,把相关的依赖关系作为值存入,比如计算属性等等,这样将响应式对象删除之后,就不用手动清除相关的依赖关系

还有的常见场景:如果使用weakMap做一些记录缓存,key是原始对象,值是缓存产物,希望对象如果被清理,那么缓存产物就会被自动清理的场景

  • WeakSet: 唯一值结构,值是弱引用,值的元素必须是对象

在遍历打包图的时候,希望通过记录,确定是否该节点曾经被引用遍历,可以用weakSet处理,这样对象被销毁的时候,会自动清除对应的标记

4. 虚拟Dom介绍一下,虚拟Dom的本质是什么

本质是一个JSON对象,希望通过轻量的json文件,来代替真实Dom,方便框架使用diff算法快速定位到变更项,来减少真实DOM的渲染损耗。

5. nextTick的作用和原理

nextTick是为了Dom更新完成之后再执行回调,确保回调里面拿到的是更新后的Dom数据。

本质上是因为vue在遇到Dom的异步操作的时候,不会立即执行,而是会将其收集起来,放到一个异步更新池内,等到所有的同步操作执行完成之后再执行异步Dom操作,因为频繁的重绘重排会影响性能。

常见应用场景:希望在拖拽完后,拿到盒子的高度。

原理实际上是vue的Dom更新和nextTick都是微任务,按照异步更新的顺序,先执行同步任务->微任务->宏任务,vue会把Dom更新操作放在一个微任务的异步队列里面(本质上是Promise.then),然后把nextTick的操作放在这个异步队列的最末尾。

6. 宏任务和微任务的区别?

宏任务:

  • 优先级较低的异步任务,也就是说如果宏任务的中途插入微任务,会中断宏任务的执行,优先先清空对应微任务,再继续执行宏任务
  • 常见宏任务:setTimeout,setTimeInterval

微任务:

  • 优先级高的异步任务,并且微任务会一次性执行完毕,适合需要即时完成的异步操作,这也是为什么Vue会用微任务处理Dom操作
  • 常见微任务:Promise,MutationObserver,async和await,nextTick

7. watch和watchEffect的区别有哪些?什么原理造成了他们的区别?

  • watch是显式监听,监听对象,监听的层级,是否立即执行都需要显式声明
  • watchEffect是隐式监听,会监听内部所有响应式对象,一旦变化,立即执行

需要明白他们的原理差异需要明确vue的响应式更新原理中的effect,effect概念比较抽象,细说就是:一个函数发生变更的时候,会获取该函数内部的响应式数据,然后之前通过weakMap建立了响应式数据和对应依赖的监听关系,于是响应式数据发生变化,会通知对应的依赖变化

watchEffect就是上面的逻辑,watch做了变更,只有显示监听会通知对应监听数据的依赖关系

8. 居中对齐说出三种

  • flex布局:justify-content:center+align-items:center
  • top:50%;left:50% + translate(-50%,-50%)

top和left是相对父元素,translate是相对于自身,(-50%,-50%)是相对于自身往上偏移自身高度的50%,往左偏移自身宽度的50%

  • margin:auto

9. Promise的常用方法有哪些?应用场景举例。

  1. promise.then 异步执行回调函数
  2. promise.catch 执行错误,异步捕获错误
  3. promise.finally 无论执行成功还是失败都需要执行的函数
  4. promise.all 等待所有的Promise都执行成功,一起返回一个结果,只要有一个执行失败就立刻返回失败结果
  5. promise.race 取第一个完成的结果,比如接口超时场景,一旦失败就立刻重试
  6. promise.allSettled 等待所有的promise的结果都完成,无论成功与否都进行返回,比如多文件上传,每个文件上传失败与否的结果都需要知道
  7. promise.any 取第一个成功的promise结果返回,失败的就不返回了,比如请求多个CDN的资源,哪个先返回资源选择哪个资源

10. vue从代码怎么构建到真实Dom渲染对象的?

  1. 编译阶段:当我们按照vue的模板构建template的时候,vue不会直接解析模板字符串,而是先把模板编译成渲染函数render()
  2. VNode生成阶段:当组件首次挂载/数据更新的时候,Vue会执行渲染函数,生成对应的VNode树,也就是虚拟DOM,一个javascript对象
  3. 挂载/更新阶段:最开始的挂载阶段,Vue通过Patch算法,遍历整个VNode树,将VNode转换成真实DOM;后续的数据更新阶段,使用Diff算法对比新旧VNode的差异,只更新变更节点的渲染

11. CSS的优先级?

important>内联样式>id选择器>类选择器>tag选择器 === 伪元素选择器

12. DOM对象上都有哪些属性?

  • tagName:dom元素的tag,比如'div'/'a'/'p'等等
  • className: dom元素的类名,比如'innerContainer flex-row'等等
  • attributs:dom元素的所有自身已有的props,比如id='treeNode'/class='innerContainer'等等
  • dataset:dom元素的所有用户自定义的props,比如selectedTestSet="[]"等等
  • innerHTML: dom元素内部的HTML内容
  • innerText:dom元素内部的文本内容
  • parentNode: 父节点元素
  • childNodes:子节点元素的集合,返回NodeList类
  • style: 返回元素的css样式

13. vue和react的区别有哪些?

首先需要纠正一些vue和react的广泛传播的误区,vue和react都属于是单向数据流,只能从父组件流向子组件,子组件要修改props数据,只能通过emit等方法,但是vue提供了props+emit封装好的的双向语法糖v-model/.sync,这导致使用者在一定程度上不需要具备单向数据流和状态管控的意识,而react不具备这样的语法糖,所有的状态管控都必须开发者声明。

这也是为什么大型项目优先选择react,需要快速开发的中后台优先选择vue的核心原因之一。

  • vue: 模板式框架

(1.1)存在大量的指令和模板语法 (1.2)无需手动触发更新,响应式是自动追踪更新 (1.3)存在生命周期的概念 (1.4)响应式粒度更细,能够精准追踪变化数据

  • react: 声明式框架

(1.1)使用jsx搭建框架 (1.2)需要手动触发更新,使用useState等声明响应式变量,使用setXXXX方法手动修改状态,react会对比新旧状态确定是否更新 (1.3)不存在生命周期的概念,统一使用useEffect处理,按照监听的对象是否有数据,是否是空数组,来决定在什么时候处理回调函数,整个过程需要手动管理依赖,不然容易出现依赖缺失问题 (1.4)响应式粒度更粗,需要手动触发更新,并且以整颗子树为维度进行更新渲染,所以一般都会绑定useMemo/useCallBack方法

14. useMemo和useCallback的区别和应用场景?

  1. useMemo和useCallback通常用于react性能优化场景,useMemo用于记忆缓存执行函数的结果,useCallback用于优化记忆缓存执行函数本身

应用场景:

  1. 对于一个物流轨迹的索引组件,只会在有新的物流信息的时候更新新信息的部分,其他部分都不需要更新,因此可以将其他部分的信息使用useMemo缓存起来,然后将该商品物流订单作为依赖项。

  2. 假设一个商品有可能存在是A,B,C仓库,现在有一段提示信息,需要显示d物品在XXX仓库里面存放,这样拼接函数就可以只在监听到仓库值变化的时候变化,不然就一直返回原拼接函数

15. useEffect的执行时机是什么?

组件卸载的时候会执行return的函数

16. useEffect的依赖不同会有什么区别?

(1.1)无依赖,每次组件渲染都会执行内部的函数

(1.2)空数组依赖,只会在挂载的时候执行

(1.3)数组内部存在变量,只会在初次挂载+变量变化的时候执行

17. react的fiber机制

fiber本质上是一个数据对象,一起构成了fiber链表,代表构建渲染单元,和调度器一起,把react的渲染过程改成“可中断,可恢复,优点级可控”的异步流程方案。