第十七节: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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

相关