ES6 Proxy和Reflect

1.Proxy是什么?

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。属于“元编程”,即对编程语言进行编程。

如对对象a进行拦截就 let p = new Proxy(obj,handler)在handler里面编写拦截逻辑;

又如有对象a和b,想要对对象a中实现拦截对象b的属性,就将对象b设置到对象a的原型上再编写拦截逻辑;

2.创建Proxy对象的两种基本语法

  • 创建对象的代理
const p = new Proxy(target, handler)
  • 创建一个可撤销的代理对象
const { proxy: p, revoke } = Proxy.revocable(data, handler)

3.创建的proxy的实例有三个属性

  • target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
  • handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。(获取或者设置属性等操作;handler函数触发时,handler函数里面的this指向handler函数)
  • IsRevoked:当前属性是否被撤销。const { proxy: p, revoke } = Proxy.revocable(data, handler)创建一个可撤销的代理对象

4.proxy的实例两个注意点:

4.1 handler函数:handler函数触发时,handler函数里面的this指向handler函数

        let obj = { a:1 };let handler = {get(target, property, receiver){console.log(this);return target[property];//get中需要返回对应属性}};let p =  new Proxy(obj,handler);console.log(p.a);//注意要通过代理对象获取才能触发 get拦截

 

4.2 IsRevoked属性

IsRevoked:当前属性是否被撤销。const { proxy: p, revoke } = Proxy.revocable(data, handler)创建一个可撤销的代理对象

通过const { proxy: p, revoke } = Proxy.revocable(data, handler)创建可被撤销的对象实例后,此时IsRevoked为false,p.a 去调用属性会返回;

当在调用revoke();方法用于撤销代理对象,调用后IsRevoked为true,p.a 去调用属性会报错;

        let obj = { a:1 };let handler = {};const { proxy, revoke } = Proxy.revocable(obj, handler);

 5.handler中的方法handler.get()

var p = new Proxy(target, {get (target, property, receiver) {}
})

5.1方法用于拦截对象的读取属性操作。

  • target表示目标对象
  • property 被获取的属性名
  • receiver 接收Proxy或者继承Proxy对象 receiver === p
        let obj = { a: 1, b: 2 };let handler = {get(target, property, receiver) {console.log(target, property, receiver);return target[property];}};let proxy = new Proxy(obj, handler);console.log(proxy.a);

 

5.2 receiver 表示get()方法中接收的对象或者继承自的proxy对象

这里的问题是代理对象proxy.name想要获取到的是obj1上的name。

5.3handler.get()方法会拦截目标对象的以下操作:

  • 访问属性:proxy[foo] 和 proxy.bar
  • 访问原型链上的属性:Object.create(proxy)[foo]
  • Reflect.get()访问属性

访问属性:proxy[foo] 和 proxy.bar

比如,使用Proxy代理对象obj2,并将proxy实例对象设置到obj1的原型上,则通过obj1就可以获取到Proxy代理后的obj2的属性。此时通过proxy.name就可以获取到obj2的属性name值"lmf"

        let obj1 = { a: 1, b: 2, name: 'allen' };let obj2 = {name: 'lmf',get value() {return this.name}}let handler = {get(target, property, receiver) {return target[property];// return Reflect.get(target, property, receiver);}};let proxy = new Proxy(obj2, handler);// 将obj2的属性设置到obj1的原型上,则通过obj1就可以获取到obj2的属性Object.setPrototypeOf(obj1, proxy);console.log(obj1);console.log(obj1.value);//lmf

 其实这里obj1.name应该为allen才对,可以通过return Reflect.get(target, property, receiver);设置,类似与改变this指向为目标对象target也就是obj1

        let obj1 = { a: 1, b: 2, name: 'allen' };let obj2 = {name: 'lmf',get value() {return this.name}}let handler = {get(target, property, receiver) {return Reflect.get(target, property, receiver);}};let proxy = new Proxy(obj2, handler);// 将obj2的属性设置到obj1的原型上,则通过obj1就可以获取到obj2的属性Object.setPrototypeOf(obj1, proxy);console.log(obj1);console.log(obj1.value);//lmf

 访问原型链上的属性:Object.create(proxy)[foo]

        // 访问原型链上的属性:Object.create(proxy)[foo]let obj1 = { foo:'foo' };let handler = {get(target, property, receiver) {console.log("触发了");return target[property]}};let proxy = new Proxy(obj1, handler);const p = Object.create(proxy);console.log(p['foo']);

 Reflect.get(proxy, property)访问属性

        //  Reflect.get()访问属性let obj1 = { foo: 'foo' };let handler = {get(target, property, receiver) {console.log("触发了");return target[property]}};let proxy = new Proxy(obj1, handler);Reflect.get(proxy, 'foo')

6.handler中的方法handler.set()

 handler.set() 方法是设置属性值操作的捕获器。

const p = new Proxy(target, {set: function(target, property, value, receiver) {}
});

该方法会拦截目标对象的以下操作

1. 指定属性值:proxy[foo] = bar 和 proxy.foo = bar

2. 指定继承者的属性值:Object.create(proxy)[foo] = bar

3. Reflect.set()

        let obj1 = {myTime : "1697683657936"}let handler = {set(target, property, value){let setTime = value + new Date().getTime();target[property] = setTime;}}let proxy = new Proxy(obj1,handler);proxy.myTime = "此时的时间戳是:";console.log(proxy.myTime);

7.利用proxy实现的功能

7.1 验证对象的传值

需要实现的功能

1. 验证age属性的数据类型是否为整数

  2. 验证值的范围是否小于等于200

        // 需要实现的功能// 1. 验证age属性的数据类型是否为整数// 2. 验证值的范围是否小于等于200let user = {age: 100}let handler = {set(target,property,value){if(property==='age'){if(!Number.isInteger(value)){throw new TypeError("age的值必须是整数");}if(value>200){throw new RangeError("age的值不能超过200");}}}}let proxy = new Proxy(user,handler);// proxy.age = 22.3;proxy.age = 300

7.2通过属性查找数组中的特定对象

 需要实现的功能

var data = [{ name: 'Firefox'    , type: 'browser' },{ name: 'SeaMonkey'  , type: 'browser' },{ name: 'Thunderbird', type: 'mailer' }
]

1. 通过索引返回对应数据 proxy[0]

2. 通过number属性返回数组长度 proxy.number

3. 通过name获取对应的数据 proxy['Firefox']

4. 通过type返回对应的数据 proxy['browser']

5. 通过types返回data中的type products.types

        var data = [{ name: 'Firefox', type: 'browser' },{ name: 'SeaMonkey', type: 'browser' },{ name: 'Thunderbird', type: 'mailer' }]let handler = {get(target, property) {// 2. 通过number属性返回数组长度 proxy.numberif (property === 'number') {return target.length;}let result = [];target.forEach((item, index) => {// 1. 通过索引返回对应数据 proxy[0]if (property == index) {return result.push(item);}// 3. 通过name获取对应的数据 proxy['Firefox']if (property === item.name) {return result.push(item);}// 4. 通过type返回对应的数据 proxy['browser']if (property === item.type) {return result.push(item);}// 5. 通过types返回data中的type products.typesif (property === 'types') {result.push(item.type);result = [...new Set(result)]}});return result;}}let proxy = new Proxy(data, handler);console.log(proxy[0]);console.log(proxy.number);console.log(proxy['Firefox']);console.log(proxy['browser']);console.log(proxy['types']);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/111332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 799. 香槟塔【数组,模拟,简单线性DP】1855

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…

开源OA协同办公系统,集成Flowable流程引擎 可拖拽创建个性表单

源码下载:https://download.csdn.net/download/m0_66047725/88403340 源码下载2: 关注我留言 开源OA协同办公系统,集成Flowable流程引擎 可拖拽创建个性表单。基于RuoYi-VUE版本开发。 1、使用RuoYi-Vue的基础上开发。 2、集成flowable&a…

ubuntu 20.04 passwd 指令不能使用

Linux 更改用户密码报Changing password for user 用户名. passwd: Module is unknown或更改新增用户密码passwd:未知的用户名 报错信息如下: 解决方法: 可以排查 /etc/pam.d/passwd配置文件 注释掉包含pam_passwdqc.so模块的行&#xff0c…

.NET开源且免费的Windows远程桌面管理软件

前言 今天要给大家推荐一款由.NET开源且免费的远程桌面管理软件:1Remote。 1Remote官方项目介绍 1Remote是一款现代的远程会话管理和启动器,它让你能够在任何时候快速开启一个远程会话。目前1Remote已支持 微软远程桌面(RDP)、VNC、SSH、Telnet、SFTP、…

Hadoop3教程(二十四):Yarn的常用命令与参数配置实例

文章目录 (132)YARN常用命令查看任务查看日志查看容器查看节点状态rmadmin更新配置查看队列 (133)生产环境核心配置参数(135)生产环境核心参数配置案例(140/141)Tool接口案例参考文献…

企业IT资产设备折旧残值如何计算

环境: 企业/公司 IT资产 问题描述: 企业IT设备折旧残值如何计算? 解决方案: 1.按三年折旧 净值原值-月折旧额折旧月份 , 月折旧额原值(1-3%)/36 折旧月份ROUND(E2*(1-3%)/36,2) 2.净值E2-F2*G2

彩虹商城知识付费程序

1,下载程序, 2.宝塔新建站点,,自己的域名直接用(别忘记解析了)教程直接用IP测试。。 3.上传你下载的压缩包(这里暂停一下,传好了继续)有点慢等不了了, 4.上传…

C语言中的3种注释方法

C语言中的3种注释方法 2021年8月28日星期六席锦 在用C语言编程时,常用的注释方式有如下几种: (1)单行注释 // … (2)多行注释 /* … */ (3)条件编译注释 #if 0…#endif (1)(2)在入门教程中比较常见。 对于(1) 【单行注释 // …】,注释只能显示…

【VR】【Unity】如何调整Quest2的隐藏系统时间日期

【背景】 网络虽然OK,但是Oculus Quest要连上商店还必须调整好系统时间,不过在Quest系统中,时间对用户是不可见的,本篇介绍调整的方法。 【方法】 打开SideQuest,没有的话先去下载一个。打开后先登录,如…

安装宝塔面板(详细教程)

一、简介 宝塔面板是一款简单好用的服务器运维面板。它支持一键LAMP/LNMP/集群/监控/网站/FTP/数据库/JAVA等100多项服务器管理功能。对于新手用云服务器来建站的话,宝塔面板是一个非常好用的工具。 宝塔官网:https://www.bt.cn/new/index.html 二、宝…

万物归宗系列01-html基本语法

万物归宗系列&#xff0c;即什么都懂一点系列。 HTML是标签语言&#xff0c;一般成双成对。 Hypertext Markup Language&#xff1a;超⽂本标记语⾔。是⽤来制作⽹页的⼀种标记语⾔。 1 基本框架 <!DOCTYPE html> <html lang"en"> <head><meta…

057:mapboxGL中layout,paint等属性的函数表达说明

第057个 点击查看专栏目录 本篇文章是mapbox的layer中layout,paint等属性的函数表达 mapbox中 Function 是什么 函数 Function 可以作为其 layout布局类属性和 paint 绘制类属性的属性值。在使用 Function 作为属性值时,实际上是一个对象。 layers的3种函数类型 Function …

根据SpringBoot Guides完成进行示例学习(详细步骤)

目录 1.打开Spring | Guides官网&#xff0c;或者直接搜索springboot都可 2.选择要学习的内容 3.根据提示的网址&#xff0c;Git到本地 4.将文件用IDEA打开&#xff0c;根据教程完成示例&#xff0c;这里不做细致讲解 5.运行项目 6.在终端查看运行结果 以Scheduling Task…

Apollo的搭建

Apollo的搭建 1.环境准备 jdk : 1.8 mysql 5.6.5 2.下载 两种方式&#xff1a; a.下载源码自己编译&#xff08;需要修改源码的可以选择&#xff09; 源码&#xff1a;https://github.com/ctripcorp/apoll b.编译好的直接使用 地址&#xff1a;Releases apol…

卷王问卷考试系统SurveyKing,开源调查问卷和考试系统源码

卷王问卷考试系统/SurveyKing是一个功能最强大的开源调查问卷和考试系统&#xff0c;可以快速部署&#xff0c;并适用于各行业。该系统提供了在线表单设计、数据收集、统计和分析等功能&#xff0c;支持20多种题型&#xff0c;多种创建问卷方式和多种问卷设置。 无论您是需要进…

力扣刷题 day49:10-19

1.二进制手表 二进制手表顶部有 4 个 LED 代表 小时&#xff08;0-11&#xff09;&#xff0c;底部的 6 个 LED 代表 分钟&#xff08;0-59&#xff09;。每个 LED 代表一个 0 或 1&#xff0c;最低位在右侧。 例如&#xff0c;下面的二进制手表读取 "4:51" 。 给你…

Linux Docker图形化工具Portainer如何进行远程访问

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

1814_ChibiOS中的时间以及时间间隔处理

全部学习汇总&#xff1a; GreyZhang/g_ChibiOS: I found a new RTOS called ChibiOS and it seems interesting! (github.com) 1. 时间的相关配置&#xff0c;有tick的计数精度、时钟频率、间隔时间精度、时间类型大小等不同的配置。这些参数&#xff0c;涉及到系统的时间计数…

日志回滚工作原理剖析及在文件系统的作用

日志回滚原理 当涉及到崩溃恢复和一致性保护时&#xff0c;日志回滚是一种常见的机制。它通过记录写入操作到一个事务日志中&#xff0c;而不是直接应用到文件系统&#xff0c;以保护文件系统的一致性。下面是日志回滚的一般工作原理&#xff1a; 日志记录&#xff1a;在进行写…

FPGA驱动SDRAM

文章目录 一.SDRAM简介&#xff08;手册分析&#xff09;1.1存储空间1.2特征1.3引脚1.4内部结构1.5需要关注的一些时间1.6模式寄存器1.7命令真值表 二.时序分析&#xff08;手册分析&#xff09;2.1Avalon时序2.2行激活时序2.3列读写时序2.4读数据2.5写数据 三.初步设计3.1状态…