前言
最近研究Vue3中reactive实现的源码中发现,通过proxy代理后,触发getter时,返回的是Reflect.get(target, key, receiver),而不是target[key]
function createGetter(isReadonly = false, shallow = false) {
return function get(target: Target, key: string | symbol, receiver: object) {
......
const res = Reflect.get(target, key, receiver)
return res
}
}
地址:packages\reactivity\src\baseHandlers.ts,函数createSetter
经过探索后发现可以用一个demo来解释使用Reflect来避免引起this指向错误问题
Demo
let father = {
_name: "father",
age: 40,
get name() {
console.log(this);
return this._name;
},
};
let fatherProxy = new Proxy(Father, {
get(target, prop, receiver) {
// return target[prop];
return Reflect.get(target, prop, receiver);
},
});
let kid = {
__proto__: fatherProxy,
_name: "kid",
age: 20,
};
console.log("kid.name", kid.name); // kid
调试可以发现
return Reflect.get(target, prop, receiver),返回的是kidreturn target[prop],返回的是father
分析
使用 Reflect.get(target, prop, receiver):
- 最重要的是
receiver这个参数,mdn上对参数receiver的解释:
- 当调用
Reflect.get时,它明确指定了receiver参数,这个参数指定了属性访问的接收者,也就是调用属性访问操作的对象。在这种情况下,调用了kid.name,所以receiver是kid对象。 Reflect.get能够正确地获取属性,并且在代理对象中,receiver参数的存在帮助代理知道在哪个对象上执行属性访问,因此this在代理中正确地指向了kid对象。
使用 target[prop]:
- 当使用
target[prop]时,它并没有指定receiver参数,而只是在target对象上直接访问属性。 - 这种方式不考虑代理对象的情况,而只关注
target对象。在代理对象fatherProxy上执行target[prop]时,它会尝试在fatherProxy上查找属性,而不是在kid上。 - 因此,
this在这种情况下会指向fatherProxy,而不是kid。
结论
receiver 参数的存在帮助代理知道在哪个对象上执行属性访问,解决了上下文错乱的问题,我的理解有点像函数的bind方法,改变了this的绑定
便捷写法
通过查询JavaScript高级程序设计这本红宝书,发现proxy+Reflect会有更便捷的写法:
new Proxy(target, {
get() {
return Reflect.get(...arguments);
},
});
-----------------------------------------
new Proxy(target, {
return Reflect.get,
});
END
- 文中有理解不到位的地方,欢迎各位的指导呀
- 希望这篇文章可以帮助到有需要的小伙伴们,有问题可以评论或私信我呀🤞🤞