vue2和vue3响应式原理浅析--应付面试本人是懒得记
Vue 2 和 Vue 3 的响应式原理在实现机制上有显著差异,这些差异直接影响了性能、开发体验和代码结构。应付面试,我是懒得记╮(╯▽╰)╭,无奈的人
文章目录
- 一、Vue 2 的响应式原理
- 核心技术:`Object.defineProperty`
- 工作流程:
- 局限性:
- 二、Vue 3 的响应式原理
- 核心技术:`Proxy` + `Reflect`
- 工作流程:
- 优势:
- 三、对比总结(可以记这里)
- 文字记录
- 四、源码简要示意
- Vue 2 示例(简化)
- Vue 3 示例(简化)
一、Vue 2 的响应式原理
核心技术:Object.defineProperty
Vue 2 使用 Object.defineProperty
来劫持数据属性的 get
和 set
方法,从而实现响应式追踪。
工作流程:
-
初始化阶段:
- 对
data
中的每个属性进行递归遍历。 - 使用
Object.defineProperty
将其转换为响应式的 getter/setter。
- 对
-
依赖收集(Dep):
- 在组件渲染时访问数据属性,触发
get
,将当前 Watcher 添加到该属性的依赖列表中。
- 在组件渲染时访问数据属性,触发
-
派发更新(Watcher):
- 当数据变化时,触发
set
,通知所有依赖的 Watcher 更新视图或执行回调。
- 当数据变化时,触发
局限性:
- 不能监听数组索引修改和 length 变化,需通过重写数组方法(如
push
、pop
等)来实现响应。 - 新增属性必须使用
$set
才能响应式化,否则不会被自动追踪。 - 初始化时需要递归处理对象,性能较差,尤其在大型对象上。
二、Vue 3 的响应式原理
核心技术:Proxy
+ Reflect
Vue 3 改用 Proxy
实现响应式系统,提供了更强大和灵活的数据劫持能力。
工作流程:
-
创建响应式对象:
- 使用
new Proxy(target, handler)
拦截对对象的操作。 handler
中定义get
、set
、deleteProperty
等操作。
- 使用
-
依赖收集与更新通知:
- 利用
WeakMap
存储对象与依赖之间的映射关系。 - 每个属性对应一个
Dep
(依赖集合),在get
时收集依赖,在set
时触发更新。
- 利用
-
嵌套响应式支持:
- 在访问嵌套属性时自动进行响应式包装。
-
副作用管理:
- 引入
effect
函数作为副作用容器,便于统一调度和清理。
- 引入
优势:
- 支持监听对象新增/删除属性,无需
$set
。 - 可监听数组索引变化和 length 修改,无需重写数组方法。
- 性能优化:只在首次访问属性时才进行响应式包装,避免 Vue2 中的递归处理。
- 拦截更多操作类型:如
in
、delete
、apply
、construct
等,扩展性强。
三、对比总结(可以记这里)
特性 | Vue 2 | Vue 3 |
---|---|---|
响应式核心 | Object.defineProperty | Proxy + Reflect |
数组支持 | 需重写方法 | 天然支持索引和 length |
新增属性 | 必须 $set | 自动响应 |
性能 | 初始化开销大 | 惰性处理,性能更好 |
依赖收集 | 组件级 Watcher | 更细粒度的依赖追踪 |
内存占用 | 较高 | 更优,利用 WeakMap |
文字记录
- Vue 2 的响应式是基于
defineProperty
的静态属性劫持,存在明显局限。 - Vue 3 的
Proxy
实现更加灵活、高效,解决了 Vue 2 的诸多痛点。 - Vue 3 的响应式系统是迈向现代化前端框架的重要一步,也为后续的 Composition API 提供了坚实基础。
四、源码简要示意
Vue 2 示例(简化)
function defineReactive(obj, key, val) {const dep = new Dep();Object.defineProperty(obj, key, {get() {Dep.target && dep.addSub(Dep.target);return val;},set(newVal) {if (val === newVal) return;val = newVal;dep.notify();}});
}
Vue 3 示例(简化)
function reactive(target) {return new Proxy(target, {get(target, key, receiver) {track(target, key); // 收集依赖return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {const result = Reflect.set(target, key, value, receiver);trigger(target, key); // 触发更新return result;}});
}