Proxy receiver的使用,为什么需要Reflect对象

为什么需要receiver

最近在看回阮一峰老师的ECMAScript6入门,在Proxy一章中提到的13种拦截方法,其中get 和 set 都有一个receiver参数,原文的解释是:原始的读/赋值操作所在的那个对象,并且有两段代码示例:

ini 复制代码
const proxy = new Proxy({}, {
  get: function(target, key, receiver) {
    return receiver;
  }
});
proxy.getReceiver === proxy // true

这一段就是解释了receiver指向原始操作对象。但是target不也是跟receiver一个指向吗,那为什么还要receiver呢,接着看第二段示例代码:

ini 复制代码
const proxy = new Proxy({}, {
  get: function(target, key, receiver) {
    return receiver;
  }
});

const d = Object.create(proxy);
d.a === d // true

这里用了一个ProxyObject.create创建d对象,那么在读取d对象的时候,由于没有自身属性,就会去原型上找,找到proxy,然后被get拦截,返回receiver,这里的receiver却是指向了d对象。

那么很明显,在这类型问题上,指向就是receiver所要解决的问题了

实际问题

既然是指向问题,那么this就是我们始终绕不开的话题,我们就用this指向来举个例子。

js 复制代码
let user = {
  _name: 'user',
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, propKey, receiver) {
    return target[propKey];
    // return Reflect.get(target, propKey);
  }
});

let admin = Object.create(userProxy);
admin._name = 'admin';

console.log(admin.name); // user

发现问题

这里的user用了_name表示name是私有的,并且使用了get函数来获取,然后Proxy拦截读取操作,返回值直接使用了对象取值的方式。然后用声明admin去继承userProxy,并且给admin自己取名为admin

然而在读取admin.name时却发现名字是user,这里非常简单,因为Proxy.get中的targetuser,所以返回的是user._name

同样的使用Reflect对象去还原原生行为,但不传入receiveradmin.name依然是user

解决问题

当我们传入receiver

js 复制代码
let user = {
  _name: 'user',
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, propKey, receiver) {
    return Reflect.get(target, propKey, receiver);
  }
});

let admin = Object.create(userProxy);
admin._name = 'admin';

console.log(admin.name); // admin

admin.name就变成了admin,这才是我们想要的结果。

为什么要用Reflect对象

这里还有一点,我们直接target[propKey]的方式能用上receiver吗?

对象的get函数,Proxy.get需要返回一个修改了this指向的函数,那可以返回target[propKey].bind(receiver)吗?

答案是不可以的,对象的get函数是比较特殊的存在,表现形式是函数,但他其实是个属性,当你访问target[propKey]的时候,他已经是user字符串了,自然的在它的原型上是找不到bind方法的。

相关推荐
图扑软件3 小时前
中篇・运笔|统一 DataModel 底座,HT UI 组件万物同源
javascript·低代码·ui·性能优化·数据可视化
a1117763 小时前
3D 脑图谱 / Bilingual 3D Brain Atlas 项目
前端
T1mzhou3 小时前
ARM64 Linux 6.10内核启动流程2-rootfs 怎么挂上
linux·服务器·前端
小小尚@4 小时前
WebGIS/ECharts 地图开发|MapLand 在线行政区划边界一键下载 GeoJSON 工具
前端·javascript·echarts
葡萄城技术团队4 小时前
工业数据可视化:使用活字格 AIcoding + Three.js 构建轻量化三维设备监控大屏
开发语言·javascript·信息可视化
默_笙5 小时前
🚍 一条 Todo 的奇幻漂流:TypeScript 全栈类型安全的"护照检查"
前端·javascript
计算机魔术师5 小时前
NVIDIA 以 129.3 亿美元收购 Hugging Face
前端
平头哥技术团队5 小时前
Day 01 | 用 HTML 写第一个网页:双击就能在浏览器打开
前端
weixin_422555426 小时前
el-menu子菜单点击就被激活,恢复之前的激活状态
javascript·vue.js·elementui
计算机魔术师6 小时前
两年翻45倍!英伟达靠买买买建成千亿投资帝国
前端