Reflect和proxy

147 阅读3分钟

Reflect

  • Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy handlers 的方法相同。Reflect 不是一个函数对象,因此它是不可构造的。
  • 特征:
    • 不可构造,不能使用 new 进行调用
    • 所有方法和 Proxy handlers 相同
    • 所有的方法都是静态方法,类似于 Math
    • 很多方法和 Ojbect 相同,但行为略微有所区别。譬如 Object.defineProperty(obj, name, desc) 在无法定义属性时,会抛出一个错误,而 Reflect. - defineProperty(obj, name, desc) 则会返回 false
  • Reflect 对象一共有 13 个静态方法(匹配 Proxy 的 13 种拦截行为)。
    1. Reflect.apply(target, thisArgument, argumentsList) 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
    2. Reflect.construct(target, argumentsList[, newTarget]) 对构造函数进行 new 操作,相当于执行 new target(...args)。
    3. Reflect.defineProperty(target, propertyKey, attributes) 和 Object.defineProperty() 类似。如果设置成功就会返回 true
    4. Reflect.deleteProperty(target, propertyKey) 作为函数的 delete 操作符,相当于执行 delete target[name]。
    5. Reflect.get(target, propertyKey[, receiver]) 获取对象身上某个属性的值,类似于 target[name]。
    6. Reflect.getOwnPropertyDescriptor(target, propertyKey) 类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符,否则返回 undefined。
    7. Reflect.getPrototypeOf(target) 类似于 Object.getPrototypeOf()。
    8. Reflect.has(target, propertyKey) 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
    9. Reflect.isExtensible(target) 类似于 Object.isExtensible().
    10. Reflect.ownKeys(target) 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受 enumerable 影响).
    11. Reflect.preventExtensions(target) 类似于 Object.preventExtensions()。返回一个 Boolean。
    12. Reflect.set(target, propertyKey, value[, receiver]) 将值分配给属性的函数。返回一个 Boolean,如果更新成功,则返回 true。
    13. Reflect.setPrototypeOf(target, prototype) 设置对象原型的函数。返回一个 Boolean, 如果更新成功,则返回 true。

proxy

  • new Proxy(target, handler) : target 被代理的对象 -- handler 被代理对象上的自定义行为

    • handler.get() 方法用于拦截对象的读取属性操作
    let obj = {
        age: 18,
        name: 'wang',
        class: ['math', 'science']
      }
      const objProxy = new Proxy(obj, {
        get: function () {
          return 'custom get'
        }
      })
      console.log(objProxy, objProxy.age);
    
    • handler.apply() 方法用于拦截函数的调用 target:Function\color{#FF7D00}{target: Function}
     function fn(a, b) {
        return a + b
      }
    
      const fnProxy = new Proxy(fn, {
        apply: function (target, thisArg, argumentsList) {
          console.log(target, thisArg, argumentsList);
          return argumentsList[0] + argumentsList[1] * 10
        },
      })
    
      console.log(fn(1, 2));  // 3
      console.log(fnProxy(1, 2));  // 21
      console.log(fnProxy.call(obj, 1, 2));  //21
    
    • handler.construct() 方法用于拦截 new 操作符 target:Function\color{#FF7D00}{target: Function}
      function con(a) {
        this.a = a;
      }
    
      function tar(a) {
        this.a = a * 10;
      }
      const conProxy = new Proxy(con, {
        construct: function (target, args) {
          console.log(target, args);
          return new tar(...args); // 必须返回一个对象
        }
      })
    
      console.log(new con(12).a);
      console.log(new conProxy(12).a);
    
    • handler.getPrototypeOf() 是一个代理(Proxy)方法,当读取代理对象的原型时,该方法就会被调用
    const monster1 = {
      eyeCount: 4
    };
    
    const monsterPrototype = {
      eyeCount: 2
    };
    
    const handler = {
      getPrototypeOf(target) {
        return monsterPrototype;
      }
    };
    
    const proxy1 = new Proxy(monster1, handler);
    
    console.log(Object.getPrototypeOf(proxy1) === monsterPrototype);
    // expected output: true
    
    console.log(Object.getPrototypeOf(proxy1).eyeCount);
    // expected output: 2
    
    
    • handler.has() 方法是针对 in 操作符的代理方法
    const handler1 = {
      has(target, key) {
        if (key[0] === '_') {
          return false;
        }
        return key in target;
      }
    };
    
    const monster1 = {
      _secret: 'easily scared',
      eyeCount: 4
    };
    
    const proxy1 = new Proxy(monster1, handler1);
    console.log('eyeCount' in proxy1);
    // expected output: true
    
    console.log('_secret' in proxy1);
    // expected output: false
    
    console.log('_secret' in monster1);
    // expected output: true
    
    
    • handler.defineProperty() 用于拦截对对象的 Object.defineProperty() 操作

    • handler.deleteProperty() 方法用于拦截对对象属性的 delete 操作。

      • deleteProperty 必须返回一个 Boolean 类型的值,表示了该属性是否被成功删除。
    • handler.getOwnPropertyDescriptor() 方法是 Object.getOwnPropertyDescriptor() 的钩子

      • getOwnPropertyDescriptor 方法必须返回一个 object 或 undefined。
    • handler.isExtensible() 方法用于拦截对对象的 Object.isExtensible()。