zoukankan      html  css  js  c++  java
  • 【JavaScript】Proxy 实例方法(一)

    以下内容为学习记录,可以参考 MDN 原文。

    环境

    • node v12.18.1
    • npm 6.14.5
    • vscode 1.46
    • Microsoft Edge 83

    概念

    Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。

    静态方法 revocable

    Proxy.revocable() 方法可以用来创建一个可撤销的代理对象。

    var revocable = Proxy.revocable({}, {
      get: function(target, name) {
        return "[[" + name + "]]";
      }
    });
    var proxy = revocable.proxy;
    console.log(proxy.foo); // "[[foo]]"
    
    revocable.revoke();
    
    console.log(proxy.foo); // TypeError is thrown
    proxy.foo = 1           // TypeError again
    delete proxy.foo;       // still TypeError
    typeof proxy            // "object", typeof doesn't trigger any trap
    

    apply

    handler.apply() 方法用于拦截函数的调用。

    function sum(a, b) {
      return a + b;
    }
    
    const handler = {
      apply: function(target, thisArg, argumentsList) {
        console.log(`Calculate sum: ${argumentsList}`);
        // expected output: "Calculate sum: 1,2"
    
        return target(argumentsList[0], argumentsList[1]) * 10;
      }
    };
    
    const proxy1 = new Proxy(sum, handler);
    
    console.log(sum(1, 2));
    // expected output: 3
    console.log(proxy1(1, 2));
    // expected output: 30
    

    construct

    handler.construct() 方法用于拦截 new 操作符。为了使 new 操作符在生成的 Proxy 对象上生效,用于初始化代理的目标对象自身必须具有 [[Construct]] 内部方法(即 new target 必须是有效的)。

    function monster1(disposition) {
      this.disposition = disposition;
    }
    
    const handler1 = {
      construct(target, args) {
        console.log('monster1 constructor called');
        // expected output: "monster1 constructor called"
    
        return new target(...args);
      }
    };
    
    const proxy1 = new Proxy(monster1, handler1);
    
    console.log(new proxy1('fierce').disposition);
    // expected output: "fierce"
    

    defineProperty

    handler.defineProperty() 用于拦截对对象的 Object.defineProperty() 操作。

    const handler1 = {
      defineProperty(target, key, descriptor) {
        invariant(key, 'define');
        return true;
      }
    };
    
    function invariant(key, action) {
      if (key[0] === '_') {
        throw new Error(`Invalid attempt to ${action} private "${key}" property`);
      }
    }
    
    const monster1 = {};
    const proxy1 = new Proxy(monster1, handler1);
    
    console.log(proxy1._secret = 'easily scared');
    // expected output: Error: Invalid attempt to define private "_secret" property
    

    deleteProperty

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

    const monster1 = {
      texture: 'scaly'
    };
    
    const handler1 = {
      deleteProperty(target, prop) {
        if (prop in target) {
          delete target[prop];
          console.log(`property removed: ${prop}`);
          // expected output: "property removed: texture"
        }
      }
    };
    
    console.log(monster1.texture);
    // expected output: "scaly"
    
    const proxy1 = new Proxy(monster1, handler1);
    delete proxy1.texture;
    
    console.log(monster1.texture);
    // expected output: undefined
    

    get

    handler.get() 方法用于拦截对象的读取属性操作。

    const monster1 = {
      secret: 'easily scared',
      eyeCount: 4
    };
    
    const handler1 = {
      get: function(target, prop, receiver) {
        if (prop === 'secret') {
          return `${target.secret.substr(0, 4)} ... shhhh!`;
        }
        return Reflect.get(...arguments);
      }
    };
    
    const proxy1 = new Proxy(monster1, handler1);
    
    console.log(proxy1.eyeCount);
    // expected output: 4
    
    console.log(proxy1.secret);
    // expected output: "easi ... shhhh!"
    

    getOwnPropertyDescriptor

    handler.getOwnPropertyDescriptor() 方法是 Object.getOwnPropertyDescriptor() 的钩子。

    const monster1 = {
      eyeCount: 4
    };
    
    const handler1 = {
      getOwnPropertyDescriptor(target, prop) {
        console.log(`called: ${prop}`);
        // expected output: "called: eyeCount"
    
        return { configurable: true, enumerable: true, value: 5 };
      }
    };
    
    const proxy1 = new Proxy(monster1, handler1);
    
    console.log(Object.getOwnPropertyDescriptor(proxy1, 'eyeCount').value);
    // expected output: 5
    

    getPrototypeOf

    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
    
  • 相关阅读:
    CharSequence的getText()与String的getString()(转)
    android 1.6 launcher研究之自定义ViewGroup (转 2011.06.03(二)——— android 1.6 launcher研究之自定义ViewGroup )
    2.1Android界面View及ViewGroup(转)
    Android笔记:百度地图与高德地图坐标转换问题
    NDK常用命令
    深入Java单例模式(转)
    CentOS 6.2 安装vsftpd 服务器(转)
    centos 安装FTP server详情(转)
    CentOS 6.3下NTP服务安装和配置
    搭建vscode+vue环境
  • 原文地址:https://www.cnblogs.com/jiangbo44/p/13682204.html
Copyright © 2011-2022 走看看