讲到Proxy对象相信大家都肯定很熟悉,vue3的响应式原理就是以此为基础的。Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
const p = new Proxy(target, handler)
handler常用方法
var p = new Proxy({},{
defineProperty(target,prop,descriptor){
console.log(111)
return Reflect.defineProperty(target,prop,descriptor)
}
})
Object.defineProperty(p,'name',{
value:'proxy',
type:'custom'
})
// console.log(p);
var desc = {
configurable:true,
enumrable:true,
value:10
}
Object.defineProperty(p,'a',desc)
console.log(p.name,p.a);
可以看到直接使用Object方法也可以实现很多业务逻辑!
那么vue的proxyHandler里为什么要使用Reflect呢?
let obj = {
x:1,
y:2
}
console.log(Reflect.get(obj,'x')) // 1
console.log(Reflect.get([1,2,3],1)) // 2
let x = {p:1}
let obj2 = new Proxy(x,{
get(t,k,r){
return k + ' is the key'
}
})
console.log(Reflect.get(obj2,'x')) // x is the key
let obj3 = {}
Reflect.set(obj3,'x',1)
console.log(obj3) // {x:1}
let arr = [1,2,3]
Reflect.set(arr,1,4)
console.log(arr) // [1,4,3]
Reflect.has({ x: 0 }, "x"); // true
Reflect.has({ x: 0 }, "y"); // false
// 如果该属性存在于原型链中,返回 true
Reflect.has({ x: 0 }, "toString");
// Proxy 对象的 .has() 句柄方法
obj = new Proxy(
{},
{
has(t, k) {
return k.startsWith("door");
},
},
);
Reflect.has(obj, "doorbell"); // true
Reflect.has(obj, "dormitory"); // false
var obj = { x: 1, y: 2 };
Reflect.deleteProperty(obj, "x"); // true
obj; // { y: 2 }
var arr = [1, 2, 3, 4, 5];
Reflect.deleteProperty(arr, "3"); // true
arr; // [1, 2, 3, , 5]
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo"); // true
// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({ foo: 1 }), "foo"); // false
这些特性使得 Reflect 在处理 Proxy 时更加方便和可靠,因此 Vue3 选择使用 Reflect 而不是 Object 的方法。
reactive.ts 中 new Proxy(target,baseHandlers)
function createReactiveObject(
// 省略很多参数
) {
// 省逻很多判断逻辑
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers,
)
proxyMap.set(target, proxy)
return proxy
}
baseHandlers 中定义了Proxy的配置项
class MutableReactiveHandler extends BaseReactiveHandler {
// ...
set(
target: Record<string | symbol, unknown>,
key: string | symbol,
value: unknown,
receiver: object,
): boolean {
// 省略一些判断
const result = Reflect.set(
target,
key,
value,
isRef(target) ? target : receiver,
)
// ...省略一些触发更新逻辑
return result
}
deleteProperty(
target: Record<string | symbol, unknown>,
key: string | symbol,
): boolean {
const result = Reflect.deleteProperty(target, key)
// 省略一些触发更新逻辑
return result
}
has(target: Record<string | symbol, unknown>, key: string | symbol): boolean {
const result = Reflect.has(target, key)
// 省略一些收集依赖逻辑
return result
}
ownKeys(target: Record<string | symbol, unknown>): (string | symbol)[] {
// 省略一些收集依赖逻辑
return Reflect.ownKeys(target)
}
}
通过分析,我们可以看到 Vue3 在其源码中大量使用了 Reflect 的方法。
比如has方法 const result = Reflect.has(target, key)
有布尔值的返回值类型,利用了Reflect有返回值的特性,并且使用了函数式的调用方式。使得代码更加简洁、可靠和易于维护。因此,Vue3 选择使用 Reflect 而不是直接使用 Object 的方法来处理 Proxy 操作。
Reflect 的这些特性使得它在处理 Proxy 时更加方便和可靠,从而提升了 Vue3 的响应式系统的性能和稳定性。
以上→