← 返回目录

第 2 卷

第 2 / 12 卷日期:

  1. 适合动态组件:对于渲染结构不固定、需要动态生成标签/属性的场景(如自定义表单、动态菜

单),JSX比template更简洁;

  1. 无缝衔接组合式API:在Vue3组合式API中,JSX可直接使用组件内的响应式数据,无需额外指令;
  2. React开发者友好:熟悉React的开发者可快速上手Vue的JSX,降低跨框架学习成本。

6. Vue中的依赖收集:触发场景与机制

一、依赖收集的触发场景

依赖收集是Vue响应式系统的核心,只有在副作用函数(Effect)执行时,访问响应式数据,才会触发依赖收集,常见场景包括:

  1. 组件渲染:组件的 render 函数(或 setup 函数中返回的渲染函数)执行时,访问响应式数据

(state、props等),会触发依赖收集;

2.computed 计算属性:初始化 computed 时,其内部的求值函数执行,访问响应式数据,触发依赖收集;

3.watch / watchEffect: watch 监听的目标数据被访问(或 watchEffect 的回调函数执行时访问响应式数据),触发依赖收集;

  1. 自定义 effect:通过 vue 暴露的 effect 函数创建自定义副作用,执行时访问响应式数据,

触发依赖收集。

二、依赖收集的核心机制

Vue2和Vue3的依赖收集机制核心思路一致,细节略有差异,整体流程如下:

通用核心流程

  1. 副作用函数包装:将需要执行的逻辑(如组件渲染、computed求值)包装为 Effect 副作用函

数;

  1. 激活Effect:执行副作用函数前,将当前 Effect 标记为“活跃状态”(全局唯一的当前副作

用);

  1. 访问响应式数据:副作用函数执行时,访问响应式数据的属性(如 obj.msg);
  2. 收集依赖:响应式数据的拦截器(Vue2: Object.defineProperty;Vue3: Proxy)感知

到属性被访问,将当前活跃的 Effect 收集到该属性的“依赖集合”中;

  1. 取消激活:副作用函数执行完毕后,取消当前 Effect 的活跃状态。

• 每个响应式对象的每个属性,对应一个 Dep 类(依赖容器),存储该属性对应的 Watcher

  • 访问属性时,触发 get 拦截器,调用 Dep.depend(),将当前 Watcher 添加到 Dep 中。

Vue3 具体实现

• 采用“靶心-属性-副作用”的映射关系: WeakMap<响应式对象, Map<属性名,

Set<Effect>>>;

• 访问属性时,触发 Proxy 的 get 拦截,调用 track 函数,沿上述映射关系,将当前活跃

Effect 添加到对应属性的 Set 集合中;

  • 依赖集合使用 Set,自动去重,避免重复收集相同的 Effect。

7. Object.defineProperty的缺点 & Vue3选择Proxy的原因

一、Object.defineProperty的潜在缺点/限制

Object.defineProperty 是Vue2实现响应式的核心API,存在以下固有缺陷:

  1. 无法监听对象属性的新增/删除:

◦ 该API只能对已存在的属性进行拦截( get / set),无法感知对象新增属性(如

obj.newKey = 123)或删除属性(如 delete obj.key);

◦ Vue2中需通过 Vue.set / this.$set、 Vue.delete / this.$delete 手动触发响应式

更新,侵入性强。

  1. 无法监听数组的原生方法与索引变化:
  • 无法感知数组索引修改(如 arr[0] = 123)和数组长度修改(如 arr.length = 0);

◦ Vue2中通过重写数组的7个变异方法(push、pop、shift、unshift、splice、sort、reverse)

来实现响应式,对于非变异方法(如slice)无法监听,索引修改仍需手动触发。

  1. 遍历对象性能较差:

◦ 若要实现对象全属性响应式,需递归遍历对象的所有属性(包括嵌套对象),对每个属性调用

Object.defineProperty,性能随对象复杂度提升而下降;

  • 无法批量处理对象属性,只能逐个拦截。
  1. 不支持Map、Set等集合类型:

◦ 该API仅适用于普通对象(Object),对于ES6新增的Map、Set、WeakMap等集合类型,无法

有效实现拦截与响应式。

二、Vue3选择Proxy的原因

◦ Proxy 拦截的是整个对象,而非单个属性,通过 set 拦截器可监听属性新增,

deleteProperty 拦截器可监听属性删除,无需手动干预;

  1. 原生支持数组监听:

◦ 可直接监听数组的索引修改、长度修改,以及所有数组方法(无需重写变异方法),通过

set、 get 拦截器即可感知数组变化;

  1. 性能更优,支持懒拦截:

◦ 无需递归遍历嵌套对象,可在 get 拦截器中按需对嵌套对象进行代理(懒加载),减少初始化

时的性能开销;

  • 可批量拦截对象的所有属性,无需逐个处理。
  1. 支持更多数据类型:

◦ 不仅支持普通对象,还支持Map、Set、WeakMap、WeakSet等ES6集合类型,以及函数等对

象类型;

  1. 拦截能力更强:

◦ Proxy 提供了13种拦截器方法(如 has、 ownKeys、 apply 等),远超

Object.defineProperty 的 get / set 拦截,能实现更复杂的响应式逻辑。

补充: Proxy 唯一的不足是不支持IE浏览器,但Vue3已放弃IE兼容,专注于现代浏览器,因此可放心使用。

8. Vue双向数据绑定的基本原理

Vue的双向数据绑定(核心指令 v-model)是单向数据绑定(数据→视图) + 事件监听(视图→数据)的封装,实现了“数据变化更新视图,视图操作更新数据”的双向联动。

一、核心原理拆解

  1. 单向数据绑定(数据→视图):
  • 底层依赖Vue的响应式系统(Vue2: Object.defineProperty;Vue3: Proxy);

◦ 当数据(如组件的 data、 props)发生变化时,响应式系统会触发依赖更新(如组件

Watcher / Effect),执行 render 函数生成新的VNode,通过 patch 函数对比虚拟 DOM,最终更新真实DOM(视图)。

  1. 事件监听(视图→数据):
  • 底层依赖DOM事件监听(如 input、 change 事件);
  • v-model 指令会自动为表单元素绑定对应的事件,并在事件回调中更新数据;
全站分卷索引 · 12 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷
  11. 11第 11 卷
  12. 12第 12 卷