当前位置: 首页 > news >正文

ES6 proxy

一 什么是proxy?

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});

obj.count = 1
//  setting count!
++obj.count
//  getting count!
//  setting count!
复制代码

上面代码对一个空对象架设了一层拦截,重定义了属性的读取(get)和设置(set)行为。这里暂时先不解释具体的语法,只看运行结果。对设置了拦截行为的对象obj,去读写它的属性,就会得到下面的结果。

上面代码说明,Proxy 实际上重载(overload)了点运算符,即用自己的定义覆盖了语言的原始定义。

ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。

var proxy = new Proxy(target, handler);


复制代码

Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

下面是另一个拦截读取属性行为的例子

var proxy = new Proxy({}, {
  get: function(target, property) {
    return 35;
  }
});

proxy.time // 35
proxy.name // 35
proxy.title // 35
复制代码

上面代码中,作为构造函数,Proxy接受两个参数。第一个参数是所要代理的目标对象(上例是一个空对象),即如果没有Proxy的介入,操作原来要访问的就是这个对象;第二个参数是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。比如,上面代码中,配置对象有一个get方法,用来拦截对目标对象属性的访问请求。get方法的两个参数分别是目标对象和所要访问的属性。可以看到,由于拦截函数总是返回35,所以访问任何属性都得到35。

注意,要使得Proxy起作用,必须针对Proxy实例(上例是proxy对象)进行操作,而不是针对目标对象(上例是空对象)进行操作。

如果handler没有设置任何拦截,那就等同于直接通向原对象。

var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';
target.a // "b"

<!-----------------------------------------------------!>

       const ma1={}
        let ma=new Proxy(ma1,{
            get:function(target,home){
                if(home==="age"){
                    return 34
                }
                return 35
            }
        })

      ma.age="a"
      ma1.age // a
      
      
      

复制代码

上面代码中,handler是一个空对象,没有任何拦截效果,访问proxy就等同于访问target。

一个技巧是将 Proxy 对象,设置到object.proxy属性,从而可以在object对象上调用。

var object = { proxy: new Proxy(target, handler) };
复制代码

Proxy 实例也可以作为其他对象的原型对象。

var proxy = new Proxy({}, {
  get: function(target, property) {
    return 35;
  }
});

let obj = Object.create(proxy);
obj.time // 35
复制代码

上面代码中,proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截。

同一个拦截器函数,可以设置拦截多个操作。

var handler = {
  get: function(target, name) {
    if (name === 'prototype') {
      return Object.prototype;
    }
    return 'Hello, ' + name;
  },

  apply: function(target, thisBinding, args) {
    return args[0];
  },

  construct: function(target, args) {
    return {value: args[1]};
  }
};

var fproxy = new Proxy(function(x, y) {
  return x + y;
}, handler);

fproxy(1, 2) // 1
new fproxy(1, 2) // {value: 2}
fproxy.prototype === Object.prototype // true
fproxy.foo === "Hello, foo" // true
复制代码

对于可以设置、但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。

下面是 Proxy 支持的拦截操作一览,一共 13 种。

二 Proxy 实例的方法

get

get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

get方法的用法,上文已经有一个例子,下面是另一个拦截读取操作的例子。

var person = {
  name: "张三"
};

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 // "张三"
proxy.age // 抛出一个错误
复制代码

上面代码表示,如果访问目标对象不存在的属性,会抛出一个错误。如果没有这个拦截函数,访问不存在的属性,只会返回undefined。

get方法可以继承。

let proto = new Proxy({}, {
  get(target, propertyKey, receiver) {
    console.log('GET ' + propertyKey);
    return target[propertyKey];
  }
});

let obj = Object.create(proto);
obj.foo // "GET foo"
复制代码

上面代码中,拦截操作定义在Prototype对象上面,所以如果读取obj对象继承的属性时,拦截会生效。

下面的例子使用get拦截,实现数组读取负数的索引。

function createArray(...elements) {
  let handler = {
    get(target, propKey, receiver) {
      let index = Number(propKey);
      if (index < 0) {
        propKey = String(target.length + index);
      }
      return Reflect.get(target, propKey, receiver);
    }
  };

  let target = [];
  target.push(...elements);
  return new Proxy(target, handler);
}

let arr = createArray('a', 'b', 'c');
arr[-1] // c
复制代码

转载于:https://juejin.im/post/5c9c313ff265da60ca587879

相关文章:

  • GocatorSDK学习笔记
  • 好程序员web前端分享JavaScript学习指南
  • MYSQL一个优化的过程
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • React:输入框新增/取消一行如何处理(X-mind图)
  • K8S 生态周报| 2019.03.25~2019.03.31
  • 无人车制胜关键:Apollo决策系统全面剖析
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • pika开源:替代WebPack的全新JS构建工具
  • MySql批量插入与唯一索引问题
  • CF451E Devu and Flowers
  • Android之RxJava详解
  • 知道大数据却不清楚工业大数据,知识架构“欠”在哪里?
  • 些许注意事项(初学)
  • 漫话:如何给女朋友解释什么是乐观锁与悲观锁
  • __proto__ 和 prototype的关系
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • echarts的各种常用效果展示
  • IDEA 插件开发入门教程
  • Java小白进阶笔记(3)-初级面向对象
  • laravel5.5 视图共享数据
  • use Google search engine
  • 从setTimeout-setInterval看JS线程
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 关于extract.autodesk.io的一些说明
  • 官方解决所有 npm 全局安装权限问题
  • 入门级的git使用指北
  • 通过git安装npm私有模块
  •  一套莫尔斯电报听写、翻译系统
  • 异步
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • 如何正确理解,内页权重高于首页?
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • #android不同版本废弃api,新api。
  • #宝哥教你#查看jquery绑定的事件函数
  • (1)bark-ml
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (八)Spring源码解析:Spring MVC
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (篇九)MySQL常用内置函数
  • (三) diretfbrc详解
  • (转)大型网站的系统架构
  • ******IT公司面试题汇总+优秀技术博客汇总
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .NET Reactor简单使用教程
  • .NET 药厂业务系统 CPU爆高分析
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .netcore如何运行环境安装到Linux服务器
  • .NET命令行(CLI)常用命令
  • .Net中wcf服务生成及调用
  • /dev下添加设备节点的方法步骤(通过device_create)