第十七节:Proxy和Reflect详解
一. Proxy详解
1. 抛砖引玉
需求:有一个对象,我们希望监听这个对象中的属性被设置或获取的过程。
解决方案:可以使用 Object.defineProperty 的存储属性描述符(set、get)来对属性的操作进行监听。
弊端:Object.defineProperty设计的初衷,不是为了去监听截止一个对象中的所有属性的。(它的初衷是为了定义普通属性,并定义属性的一些特点,可写、可遍历等)
另外:如果我们想监听更加丰富的操作,比如新增、删除属性,Object.defineProperty是无能无力的。
{ console.log("---------------------1. 抛砖引玉---------------------"); const obj = { name: "ypf", age: 20, }; // 遍历监听每个属性 Object.keys(obj).forEach(key => { let myValue = obj[key]; Object.defineProperty(obj, key, { get() { console.log(`监听到obj对象的${key}属性被访问了`); return myValue; }, set(newValue) { console.log(`监听到obj对象的${key}属性被设置值`); myValue = newValue; }, }); }); obj.name = "ypf"; console.log(obj.age); }
2. Proxy含义
ES6中,新增了Proxy代理类,如果我们想监听一个对象的相关操作,就可以基于该对象创建一个Proxy代理对象,之后对该对象的所有操作(如:修改、获取等),都通过代理对象完成,并且代理对象可以监听到我们对原对象进行的那些操作。
3. Proxy的基本使用
(1). 如何创建代理对象?
标准格式: const p = new Proxy(target,handler); target表示需要被代理的对象,hander中用来配置一下捕获器,用来监听对象
比如:我要监听obj对象,则 const objProxy=new Proxy(obj,{});
注意:后续对象的操作,都需要通过代理对象来进行,否则无法触发监听
(2). 最常用的get和set捕获器
用来监听属性的读、写 操作
A. get(target, key, receiver) 参数含义依次为:被监听(代理)的对象、被获取属性的key、调用的代理对象(即obj)
B. set(target, key, newValue, receiver) 参数含义依次为:被监听(代理)的对象、被获取属性的key、调用的代理对象
代码分享:{ console.log("--------2. 使用proxy监听对象的获取和设置操作----------"); const obj = { name: "ypf", age: 20, }; const objProxy = new Proxy(obj, { // 获取时的捕获器 get(target, key) { console.log(`监听到obj对象的${key}属性被访问了`); return target[key]; }, // 设置值时的捕获器 set(target, key, newValue) { console.log(`监听到obj对象的${key}属性被设置值`); target[key] = newValue; }, }); // 下面设置和获取属性都需要通过代理对象进行 objProxy, 否则无法触发监听 objProxy.name = "ypf1"; console.log(objProxy.age); }
4. Proxy其它捕获器
(1). has(): in 操作符的捕捉器
(2). deleteProperty(): delete 操作符的捕捉器
(3). apply(): 函数调用操作的捕捉器
(4). construct(): new 操作符的捕捉器
共有13个捕获器:
代码分享1:
代码分享2:
5. 捕获器receiver参数的作用
如下例子:改变了上面obj对象中this为ObjProxy,所以下面会调用两次 name一次,_name一次 (如果不传递receiver参数,只监听name,不监听_name)
6. 补充几个使用场景?
(1). 读操作的拦截--做非空判断
之前需要每个属性使用 || 或 ??,现在只需在代理对象的get捕获器中统一判断就行
(2). 写操作的拦截--服务端获取的数据希望是只读,不允许在任何一个环节被修改
之前遍历key,使用Object.defineProperty,设置writable: false,
现在只需要在代理的set捕获器中return false
(3). 格式校验
之前的校验都写在业务中,现在可以使用proxy分离
(4). 实例一个对象,每个对象都有一个自己的 id 而且只读
二. Reflect详解
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。