面试题答案
一键面试1. Vue 响应式系统与虚拟 DOM 的协同工作流程
- 响应式系统触发:当数据发生变化时,Vue 的响应式系统通过
Object.defineProperty()
或Proxy
捕获到数据的变动。例如,对于一个对象data = {name: 'John'}
,当data.name = 'Jane'
时,响应式系统监听到这个变化。 - 重新渲染:响应式系统会通知依赖收集过程中关联的
Watcher
实例,Watcher
会触发组件的重新渲染。在重新渲染过程中,Vue 会基于当前数据状态生成新的虚拟 DOM 树。 - 虚拟 DOM 的 diff 算法:
- 对比新旧虚拟 DOM:Vue 会将新生成的虚拟 DOM 与旧的虚拟 DOM 进行对比。diff 算法会从根节点开始,采用深度优先遍历的方式,逐层对比两个树的节点。
- 节点对比策略:
- 相同节点:如果两个节点是相同类型(标签名相同且 key 相同,如果有 key 的话),则继续对比子节点。
- 不同节点:如果节点类型不同,直接将旧节点对应的真实 DOM 替换为新节点对应的真实 DOM。例如,旧节点是
<div>
,新节点是<p>
,则直接替换。
- 子节点对比:对于子节点列表,diff 算法会采用更复杂的策略。它会尽量复用相同的子节点,减少真实 DOM 的操作。例如,通过 key 来识别子节点是否为同一节点,若子节点没有 key,可能会导致不必要的 DOM 移动。
- 更新真实 DOM:通过 diff 算法找出差异后,Vue 会将这些差异应用到真实 DOM 上,只更新那些真正需要变化的部分,从而实现高效更新。
2. 复杂嵌套组件结构中深层嵌套数据变化的处理
- 响应式原理处理深层嵌套数据:
- 对象嵌套:对于对象的深层嵌套,Vue 2 中通过递归遍历对象的属性来设置
Object.defineProperty()
进行数据劫持。例如,对于data = {user: {name: 'John', age: 30}}
,会对user
对象的name
和age
属性都设置劫持。Vue 3 采用Proxy
则可以更方便地处理深层嵌套对象,因为Proxy
是对整个对象进行代理,而不是对每个属性单独劫持。 - 数组嵌套:对于数组,Vue 会重写数组的原型方法(如
push
、pop
等),当调用这些方法时会触发响应式更新。在深层嵌套的数组结构中,同样适用此机制。
- 对象嵌套:对于对象的深层嵌套,Vue 2 中通过递归遍历对象的属性来设置
- 虚拟 DOM 机制的应用:
- 组件更新:当深层嵌套数据变化时,响应式系统触发组件重新渲染,生成新的虚拟 DOM。在复杂嵌套组件结构中,每个组件都有自己的虚拟 DOM 树。
- 逐层对比:虚拟 DOM 的 diff 算法会从最外层组件开始,逐层对比新旧虚拟 DOM 树。对于嵌套的子组件,同样会进行深度优先遍历对比。由于虚拟 DOM 的树形结构与组件的嵌套结构相对应,所以能准确找到发生变化的子树。
- 精准更新:通过 diff 算法找到深层嵌套结构中变化的节点后,Vue 会精准地更新对应的真实 DOM,即使在复杂的嵌套组件结构中,也能保证视图的准确更新。