# Proxy 与 Reflect
# Proxy
理解就是对目标的透明包装器,改变代理 目标也会改变
内部方法 | Handler 方法 | 何时触发 |
---|---|---|
[[Get]] | get | 读取属性 |
[[Set]] | set | 写入属性 |
[[HasProperty]] | has in | 操作符 |
[[Delete]] | deleteProperty | delete 操作符 |
[[Call]] | apply | 函数调用 |
[[Construct]] | construct | new 操作符 |
[[GetPrototypeOf]] | getPrototypeOf | Object.getPrototypeOf |
[[SetPrototypeOf]] | setPrototypeOf | Object.setPrototypeOf |
[[IsExtensible]] | isExtensible | Object. |
[[PreventExtensions]] | preventExtensions | Object.preventExtensions |
[[DefineOwnProperty]] | defineProperty | Object.defineProperty, Object. |
[[GetOwnProperty]] | getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor, for..in, Object.keys/values/entries |
[[OwnPropertyKeys]] | ownKeys | Object.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in, Object.keys/values/entries |
注意⚠️ 很多方法需要返回
true
或者false
比如set
delete
# Reflect
是对目标的反射 包含了目标的所有内部方法,Reflect能够调用这些内部方法。
为什么 Relect
更好?
let user = {
_name : "xiaowo",
get name (){
return this._name
}
}
const userProxy = new Proxy(user,{
get(t,p,r){
return t[p] // *
}
})
const admin = {
__proto__:userProxy,
_name:"jack"
}
console.log(admin.name) //xiaowo ???
问题出在 * 这一行
当读取admin.name 的时候 会触发代理的 get 而这时的 get 捕获器中的 target 是 user ,因为 prop 是一个getter的话将在原始对象 this=target 的上下文中执行,所以需要reflect 去拿到当前的对象。
改写后
let user = {
_name : "xiaowo",
get name (){
return this._name
}
}
const userProxy = new Proxy(user,{
get(t,p,r){
return Reflect.get(t,p,r) // * r = admin
}
})
const admin = {
__proto__:userProxy,
_name:"jack"
}
console.log(admin.name) //jack
# Proxy 的局限性
# 内部插槽(internal slot)
像是 Map Set Date Promise 都有内部插槽,类似于属性 可以由内部方法去访问,而不是通过 [[Get]]/[[Set]] 去操作,所以Proxy 无法代理到他们。
比如 Map 会将 item 放到 [[MapData]] 中,内建方法
但是可以通过 bind 绑定到原 Map 上 Vue3中有介绍
let map = new Map();
let proxy = new Proxy(map,{
get(target,prop,receiver){
let value = Reflect.get(...arguments)
console.log(value)
return typeof value === 'function' ? value.bind(target):value
}
})
proxy.set('test', 1);
alert(proxy.get('test')); // 1(工作了!)
# Proxy != target
对象是无法严格相等的,一个对象严格等于只有自己
# 总结
Proxy 是对象的包装器,将代理上的操作转发到对象,并可以选择捕获其中一些操作。
Proxy 可以代理任何对象类型的属性,包括类,函数
Proxy有13种操作方法,包括get ,set, new的construct,函数的apply
Reflect是为了补充Proxy 对于Proxy的操作方法都有一个Reflect的调用,将调用转发给目标对象
Proxy 无法代理 内部插槽(属性),需要bind到代理前的对象(目标对象)
Proxy和目标对象不相等,对象只严格相等于自己。