ES6知识点-Proxy和Reflect

3.9Proxy和Reflect

3.9.1Proxy 概述

  • 用于修改某些操作的默认行为
  • 属于一种“元编程”(meta programming),即对编程语言进行编程
  • Proxyk可理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截
  • 因此提供了一种机制,可以对外界的访问进行过滤和改写
  • 常见的 Proxy 支持的拦截操作方法
    • get(target, propKey, receiver) 拦截对象属性的读取
    • set(target, propKey, value, receiver) 拦截对象属性的设置,返回一个布尔值。
    • has(target, propKey) 拦截propKey in proxy的操作,以及对象的hasOwnProperty方法,返回一个布尔值。
    • deleteProperty(target, propKey) 拦截delete proxy[propKey]的操作,返回一个布尔值。
    • apply(target, object, args) 拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
    • construct(target, args) 拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

3.9.2Proxy实例方法

  • get() 用于拦截某个属性的读取操作

    var person = {
      name: "jack"
    };
    var proxy = new Proxy(person, {
      get: function(target, property) {
        if (property in target) {       
          return target[property];
        } else {       
          throw new ReferenceError("Property \"" + property + "\" does not exist.");
        }
      }
    });
    proxy.name     // "jack"
    proxy.age     // 抛出一个错误
    //结果分析:如果访问目标对象不存在的属性,会抛出一个错误。
    //如果没有这个拦截函数,访问不存在的属性,只会返回undefined。
  • set() 来拦截某个属性的赋值操作。

    let obj = {
      set: function(obj, prop, value) {
        if (prop === 'age') {
          if (!Number.isInteger(value)) {
            throw new TypeError('错误信息:不是整数');
          }
          if (value > 200) {
            throw new RangeError('错误信息:年龄大于200');
          }
        }
        // 对于age以外的属性,直接保存
        obj[prop] = value;
      }
    };
    let person = new Proxy({}, obj);
    person.age = 13;
    person.age     // 13
    person.age = 'jack'     // age不是整数报错
    person.age = 300     // age大于200报错
  • apply() 拦截函数的调用、call和apply操作

    apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组

    var twice = {
      apply (target, ctx, args) {
        return Reflect.apply(...arguments) * 2;
      }
    };
    
    function sum (num) {
      return num + 1 ;
    };
    
    var proxy = new Proxy(sum, twice);        // 第一个参数相当于原值,第二个参数相当于过滤器,变量proxy相当于过滤后的值
    
    proxy(2)     // 6
    proxy.call(null, 5, 6)     // 22
    proxy.apply(null, [7, 8])     // 30
  • has()

    - 用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。

    - 典型的操作就是in运算符。

    var handler = {
      has (target, key) {
        if (key[0] === '_') {
          return false;
        }
        return key in target;
      }
    };
    var target = { _prop: 'foo', prop: 'foo' };
    var proxy = new Proxy(target, handler);
    console.log(  '_prop' in proxy  )        // false
  • construct()

    • 用于拦截new命令。

    • 可以接受两个参数。

      • target: 目标对象
      • args:构建函数的参数对象
      var p = new Proxy(function() {}, {
        construct: function(target, args) {
          console.log('called: ' + args.join(', '));
          return { value: args[0] * 10 };
        }
      });
      new p(1).value
      // "called: 1"
      // 10
  • deleteProperty()

    • 方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除
    var handler = {
      deleteProperty (target, key) {
        invariant(key, 'delete');
        return true;
      }
    };
    function invariant (key, action) {
      if (key[0] === '_') {
        throw new Error('删除下划线开头的报错');
      }
    }
    var target = { _prop: 'foo' };
    var proxy = new Proxy(target, handler);
    delete proxy._prop            // 报错内容:删除下划线开头的报错

3.9.3Reflect概述

  • Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上

  • Reflect 对象使用函数的方式实现了 Object 的命令式操作

  • Reflect.get(target, name, rec)

    • 查找并返回 target 对象的 name 属性。

    • 可以有三个参数,target必须为对象类型,name是target的属性,rec为另一个对象

      let obj = {
          name: "jack",
          age: 14,
          get userInfo(){
              return this.name + this.age;
          }
      }
      
      Reflect.get(obj, 'name');     // "jack"
      
      // 当 target 对象中存在getter 方法, getter 方法的 this 会指向  rec参数的name属性
      let receiver = {
          name: "haha",
          age: 13
      }
      
      Reflect.get(obj, 'userInfo', receiver);     // haha13
      
      //  target 对象不存在该属性,返回 undefined
      Reflect.get(obj, 'aaa');     // undefined
      
      // 当 target 不是对象时,会报错
      Reflect.get(1, 'name');     //  报错
  • Reflect.set(target, name, value, receiver)

    • 将 target 的 name 属性设置为 value。

    • 返回值为true 表示修改成功,false 表示失败。

    • 当 target 为不存在的对象时即报错。

      let obj= {
          name: "jack",
          age: 24,
          set userInfo(value){
              return this.name = value;
          }
      }
      
      obj.name;      // jack
      Reflect.set(obj, 'name', "haha"); 
      obj.name;     // haha
      
      // value值为空,表示删除属性
      Reflect.set(obj, 'name', ); 
      obj.name;       // undefined
      
      // 当 target对象有set方法,setter 方法中的指向receiver, 所以修改的实际上是 receiver 的属性
      let receiver = {
          name: 8888888888
      }
      
      Reflect.set(obj, 'userInfo', "这是修改后的值", receiver);
      receiver.name;         // 这是修改后的值

猜你喜欢

转载自www.cnblogs.com/xuzhengguo/p/12045741.html