Proxy 的原理
- Proxy 是什么
Proxy 是 ES6 引入的一个新特性,它可以对对象的基本操作(如属性读取、属性设置、枚举、函数调用等)进行拦截和自定义处理。Proxy 接收两个参数:目标对象(target)和处理程序对象(handler)。处理程序对象中可以定义各种拦截操作的方法,这些方法被称为陷阱(trap)。
以下是一个简单的 Proxy 示例:
const target = {
name: 'John',
age: 30
};
const handler = {
get(target, property) {
console.log(`Getting property ${property}`);
return target[property];
},
set(target, property, value) {
console.log(`Setting property ${property} to ${value}`);
target[property] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
// 读取属性
console.log(proxy.name); // 会触发 get 陷阱
// 设置属性
proxy.age = 31; // 会触发 set 陷阱
2. Vue 3 中 Proxy 的应用原理
2.1 响应式数据创建
在 Vue 3 中,reactive 函数利用 Proxy 来创建响应式对象。reactive 函数接收一个普通对象作为参数,然后返回一个被 Proxy 包装后的对象。
以下是简化后的 reactive 实现思路:
function reactive(target) {
const handler = {
get(target, property, receiver) {
// 收集依赖
track(target, property);
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
const oldValue = target[property];
const result = Reflect.set(target, property, value, receiver);
if (result && oldValue!== value) {
// 触发更新
trigger(target, property);
}
return result;
}
};
return new Proxy(target, handler);
}
2.2 依赖收集(track)
当访问响应式对象的属性时,Proxy 的 get 陷阱会被触发。在 get 陷阱中,Vue 会收集依赖,也就是记录哪些副作用(如组件的渲染函数)依赖于这个属性。
以下是简化后的 track 函数实现:
const targetMap = new WeakMap();
function track(target, property) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(property);
if (!dep) {
depsMap.set(property, (dep = new Set()));
}
dep.add(activeEffect);
}
2.3 触发更新(trigger)
当修改响应式对象的属性时,Proxy 的 set 陷阱会被触发。在 set 陷阱中,Vue 会检查属性值是否发生了变化,如果发生了变化,就会触发依赖更新,也就是执行之前收集的所有依赖该属性的副作用。
以下是简化后的 trigger 函数实现:
function trigger(target, property) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(property);
if (dep) {
dep.forEach(effect => effect());
}
}
- 总结
Vue 3 利用 Proxy 的拦截功能实现了响应式系统。当访问响应式对象的属性时,Proxy 的 get 陷阱会收集依赖;当修改属性时,Proxy 的 set 陷阱会触发依赖更新。这种机制使得 Vue 能够自动追踪数据的变化,并在数据变化时更新相关的 DOM。与 Vue 2 中使用的 Object.defineProperty 相比,Proxy 可以拦截更多的操作,并且可以对整个对象进行拦截,不需要对每个属性进行单独处理,因此实现更加简洁和高效。
本文来自博客园,作者:jialiangzai,转载请注明原文链接:https://www.cnblogs.com/zsnhweb/p/18804999

浙公网安备 33010602011771号