Vue 3 的响应式设计原理主要基于 Proxy 和 Reflect,相较于 Vue 2 的 Object.defineProperty,Vue 3 的响应式系统更加高效和灵活。
核心原理
-
Proxy:
Proxy是 ES6 引入的一个特性,用于创建一个对象的代理,从而实现对对象操作的拦截和自定义。- Vue 3 使用
Proxy来拦截对对象属性的读取、赋值、删除等操作,从而实现响应式。
-
Reflect:
Reflect是 ES6 引入的一个内置对象,提供了与Proxy拦截操作相对应的方法。- Vue 3 使用
Reflect来执行默认的操作,确保在拦截操作后,行为与原生操作一致。
响应式系统的实现
-
Reactive:
reactive函数用于将一个普通对象转换为响应式对象。- 通过
Proxy拦截对象的读取和赋值操作,当读取属性时,收集依赖;当赋值属性时,触发更新。
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; }, deleteProperty(target, key) { const result = Reflect.deleteProperty(target, key); trigger(target, key); // 触发更新 return result; } }); } -
Effect:
effect函数用于定义副作用函数,当依赖的响应式数据发生变化时,副作用函数会自动重新执行。- Vue 3 使用
effect来实现组件的渲染和计算属性的更新。
let activeEffect; function effect(fn) { activeEffect = fn; fn(); // 首次执行,收集依赖 activeEffect = null; } function track(target, key) { if (activeEffect) { // 将 activeEffect 添加到依赖集合中 } } function trigger(target, key) { // 从依赖集合中取出对应的 effect 并执行 } -
Ref:
ref函数用于将一个基本类型的值转换为响应式对象。ref内部使用reactive来包装一个对象,对象的value属性是响应式的。
function ref(value) { return reactive({ value }); }
总结
Vue 3 的响应式系统通过 Proxy 和 Reflect 实现了对对象属性的精细拦截,能够更高效地追踪依赖和触发更新。相比于 Vue 2 的 Object.defineProperty,Vue 3 的响应式系统不仅支持数组和动态添加的属性,还能更好地处理嵌套对象和性能优化。