优雅而高效的JavaScript——Proxy 和 Reflect

在这里插入图片描述
🤔博主:小猫娃来啦
文章核心:优雅而高效的JavaScript——Proxy 和 Reflect

文章目录

  • Proxy 和 Reflect是什么
  • Proxy
    • 创建 Proxy 对象
    • 拦截器方法
    • 拦截器示例:属性拦截
    • 拦截器示例:方法拦截
  • Reflect
    • Reflect 的静态方法
    • Reflect 示例:拦截对象操作
    • Reflect 示例:操作原型链
  • Proxy 和 Reflect 的应用
    • 对象代理
    • 元编程
  • 总结

Proxy 和 Reflect是什么

Proxy 和 Reflect 是两个强大的功能,它们可以为我们提供了更大的灵活性和控制力,以创建自定义行为的对象代理和实现元编程的功能。Proxy 是用于创建对象代理的特性,它可以拦截并操作对象的底层操作。Reflect 是一个内置对象,提供了一组静态方法,用于执行与 Proxy 相关的默认行为。


Proxy

创建 Proxy 对象

要创建一个 Proxy 对象,我们使用 Proxy 构造函数,并传入两个参数:目标对象和一个处理程序对象。目标对象是被代理的对象,处理程序对象定义了在拦截器方法中实现的自定义行为。

const target = {}; // 目标对象
const handler = {}; // 处理程序对象
const proxy = new Proxy(target, handler);

拦截器方法

在处理程序对象中,我们可以定义一组拦截器方法。每个拦截器方法对应一个底层操作,当执行底层操作时,拦截器方法将会被触发。

以下是一些常见的拦截器方法:

  • get(target, property, receiver): 拦截对象的属性读取操作。
  • set(target, property, value, receiver): 拦截对象的属性写入操作。
  • apply(target, thisArg, argumentsList): 拦截函数的调用操作。
  • construct(target, argumentsList, newTarget): 拦截类的实例化操作。

拦截器示例:属性拦截

让我们通过一个示例来理解属性拦截。

const target = {name: 'John',age: 30
};const handler = {get(target, property, receiver) {console.log(`读取属性:${property}`);return target[property];},set(target, property, value, receiver) {console.log(`设置属性:${property} = ${value}`);target[property] = value;return true;}
};const proxy = new Proxy(target, handler);console.log(proxy.name); // 读取属性:name,输出:Johnproxy.age = 35; // 设置属性:age = 35
console.log(proxy.age); // 读取属性:age,输出:35

在上面的代码中,我们创建了一个目标对象 target,并定义了一个处理程序对象 handler,其中的 get 和 set 方法分别用于拦截属性的读取和写入操作。通过创建 Proxy 对象 proxy,我们可以访问目标对象的属性,并在每个操作上触发拦截器方法。

拦截器示例:方法拦截

除了属性拦截,我们还可以使用拦截器方法拦截函数的调用操作。让我们看一个例子:

const target = {sum(x, y) {return x + y;}
};const handler = {apply(target, thisArg, argumentsList) {console.log('调用 sum 方法');return target.sum(...argumentsList);}
};const proxy = new Proxy(target, handler);console.log(proxy.sum(2, 3)); // 调用 sum 方法,输出:5

在上面的代码中,我们定义了一个目标对象 target,其中的 sum 方法接受两个参数并返回它们的和。使用 apply 拦截器方法,我们可以在每次调用 sum 方法时触发一些自定义行为。


Reflect

Reflect 的静态方法

Reflect 是一个内置对象,提供了一组静态方法,用于执行与 Proxy 相关的默认行为。这些方法与拦截器方法相对应,它们提供了一种简单的方式来调用默认行为,而不是完全重写拦截器方法。

以下是一些 Reflect 的静态方法:

  • Reflect.get(target, property, receiver): 访问指定对象的属性。
  • Reflect.set(target, property, value, receiver): 设置指定对象的属性。
  • Reflect.apply(target, thisArg, argumentsList): 调用指定的函数。
  • Reflect.construct(target, argumentsList, newTarget): 创建指定类的实例。

Reflect 示例:拦截对象操作

让我们通过一个示例来理解如何使用 Reflect 的方法来拦截对象操作。

const target = {name: 'John',age: 30
};const handler = {get(target, property, receiver) {console.log(`读取属性:${property}`);return Reflect.get(target, property, receiver);},set(target, property, value, receiver) {console.log(`设置属性:${property} = ${value}`);return Reflect.set(target, property, value, receiver);}
};const proxy = new Proxy(target, handler);console.log(proxy.name); // 读取属性:name,输出:Johnproxy.age = 35; // 设置属性:age = 35
console.log(proxy.age); // 读取属性:age,输出:35

在上面的代码中,我们使用 Reflect 的 get 和 set 方法在拦截器方法中调用默认行为。通过使用 Reflect,我们可以避免完全重写拦截器方法,而只关注需要自定义的行为。

Reflect 示例:操作原型链

除了拦截对象属性的读写操作,Reflect 还提供了一些方法来操作原型链。让我们看一个例子:

class Person {constructor(name) {this.name = name;}
}const handler = {has(target, property) {console.log(`检查属性:${property}`);return Reflect.has(target, property);},get(target, property, receiver) {console.log(`读取属性:${property}`);return Reflect.get(target, property, receiver);}
};const proxy = new Proxy(Person, handler);console.log('name' in proxy); // 检查属性:name,输出:trueconst john = new proxy('John');
console.log(john.name); // 读取属性:name,输出:John

在上面的代码中,我们创建了一个 Person 类,并使用 has 和 get 方法拦截了原型链操作。通过创建 Proxy 对象 proxy,并将 Person 类传递给它,我们可以在每次操作原型链时触发自定义行为。


Proxy 和 Reflect 的应用

对象代理

通过使用 Proxy 和 Reflect,我们可以创建对象代理来拦截和加工对象的底层操作。

例如,我们可以使用 Proxy 来创建一个简单的缓存代理:

const cache = new Map();const handler = {get(target, property, receiver) {if (cache.has(property)) {console.log(`从缓存中读取属性:${property}`);return cache.get(property);}const value = Reflect.get(target, property, receiver);cache.set(property, value);console.log(`将属性缓存:${property}`);return value;},set(target, property, value, receiver) {console.log(`设置属性:${property} = ${value}`);cache.set(property, value);return Reflect.set(target, property, value, receiver);}
};const obj = new Proxy({}, handler);obj.name = 'John'; // 设置属性:name = John
console.log(obj.name); // 从缓存中读取属性:name,输出:Johnobj.name = 'Jane'; // 设置属性:name = Jane
console.log(obj.name); // 从缓存中读取属性:name,输出:Jane

在上面的代码中,我们创建了一个对象代理,它使用一个 Map 缓存对象的属性。在拦截器方法中,我们首先检查缓存中是否存在属性值,如果有,我们直接从缓存中读取。否则,我们使用 Reflect.get 方法获取属性值,并将其存储到缓存中。

元编程

元编程是指编写能够操作自身行为的代码。

通过使用 Proxy 和 Reflect,我们可以实现一些元编程的功能,例如动态属性访问、属性校验、方法调用等。

让我们看一个示例,使用 Proxy 实现动态属性访问:

const person = {name: 'John',age: 30
};const handler = {get(target, property) {if (!(property in target)) {throw new Error(`属性不存在:${property}`);}return Reflect.get(target, property);}
};const proxy = new Proxy(person, handler);console.log(proxy.name); // John
console.log(proxy.age); // 30
console.log(proxy.city); // 抛出错误:属性不存在:city

在上面的代码中,我们使用 Proxy 实现动态属性访问。在处理程序对象的 get 方法中,我们首先检查属性是否存在于目标对象中。如果不存在,我们抛出一个错误。否则,我们使用 Reflect.get 方法获取属性值。


总结

Proxy 和 Reflect 是 JavaScript 中强大的特性,它们为我们提供了更大的灵活性和控制力来创建自定义行为的对象代理和实现元编程的功能。在本文中,我们学习了 Proxy 和 Reflect 的基本概念,介绍了它们的使用方法和示例。我们还探讨了 Proxy 和 Reflect 的应用领域,包括对象代理和元编程。希望通过本文的学习,你对 Proxy 和 Reflect 的概念和用法有了更深入的理解。

在这里插入图片描述


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

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

相关文章

ESP32单片机环境搭建(VScode + PlatformIO IDE)

一、环境搭建(VScode PlatformIO IDE) 1、官网下载VScode; 2、安装最新的插件(C/C、PlatformIO IDE、python、Chinese); 3、在PlatformIO IDE中新建工程:Platforms——Projects——Create New Project——…

P2251 质量检测

题目&#xff1a; P2251 质量检测 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码&#xff1a; #include<iostream> #include<cstdio> #include<deque> #include<vector> typedef long long ll; const ll N 1e7; using namespace std;int main…

SPI 接口 CAN协议控制器 MCP2515/DP2515国产替代芯片DPC15

can控制器是CAN局域网控制器的简称&#xff0c;为解决现代汽车中众多测量控制部件之间的数据交换而开发的一种串行数据通信总线。 CAN 可提供高达1Mbit/s的数据传输速率&#xff0c;这使实时控制变得非常容易。另外&#xff0c;硬件的错误检定特性也增强了CAN的抗电磁干扰能力…

[MQ]Win平台RocketMQ安装启动

1、下载 官网下载地址&#xff1a;https://rocketmq.apache.org/zh/download 2、解压ZIP包 解压rocketmq-all-x.x.x-bin-release.zip到目录。 比如我解压到了E:\Env\MQ_rocket\rocketmq-all-5.1.4-bin-release 3、配置环境变量 ROCKETMQ_HOME 4、RocketMQ JVM内存配置 这个需要…

架构案例2017(五十二)

第5题 阅读以下关于Web系统架构设计的叙述&#xff0c;在答题纸上回答问题1至问题3.【说明】某电子商务企业因发展良好&#xff0c;客户量逐步增大&#xff0c;企业业务不断扩充&#xff0c;导致其原有的B2C商品交易平台己不能满足现有业务需求。因此&#xff0c;该企业委托某…

上网冲浪发现多处XSS

突然的发现 今天上网冲浪&#xff0c;突然想起来有一种神器&#xff0c;叫废话生成器&#xff0c;之前是在哪里下了个软件玩了一下&#xff0c;然后就给删除了&#xff0c;因为我觉得这个软件不过就是调用了一个web接口实现的&#xff0c;一个网页能解决的事还要我下一个软件。…

系列八、Redis的事务

一、是什么 可以一次执行多个命令&#xff0c;本质是一组命令的集合。一个事务中的所有命令都会序列化&#xff0c;按顺序地串行化执行而不会被其他命令插入&#xff0c;不允许加塞。 二、能干嘛 一个队列中&#xff0c;一次性、顺序性、排他性的执行一些列命令。 三、怎么玩…

【ARM Coresight Debug 系列 16 -- Linux 断点 BRK 中断使用详细介绍】

文章目录 1.1 ARM BRK 指令1.2 BRK 立即数宏定义介绍1.3 断点异常处理流程1.3.1 el1_sync_handler1.3.2 el1_dbg 跟踪 1.4 debug 异常处理函数注册1.4.1 brk 处理函数的注册 1.1 ARM BRK 指令 ARMv8 架构的 BRK 指令是用于生成一个软件断点的。当处理器执行到 BRK 指令时&…

倒计时4天|超硬核!第四届CID大会完整议程揭晓

CID大会官网&#xff1a; http://chinacid.org/ 原文链接&#xff1a;报名继续 | 超硬核&#xff01;第四届CID大会完整议程揭晓

TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化

作为一款在 Java 开发社区中广受欢迎的技术框架&#xff0c;SpringBoot 在开发者和企业的具体实践中应用广泛。具体来说&#xff0c;它是一个用于构建基于 Java 的 Web 应用程序和微服务的框架&#xff0c;通过简化开发流程、提供约定大于配置的原则以及集成大量常用库和组件&a…

使用Pytorch实现频谱归一化生成对抗网络(SN-GAN)

自从扩散模型发布以来&#xff0c;GAN的关注度和论文是越来越少了&#xff0c;但是它们里面的一些思路还是值得我们了解和学习。所以本文我们来使用Pytorch 来实现SN-GAN 谱归一化生成对抗网络是一种生成对抗网络&#xff0c;它使用谱归一化技术来稳定鉴别器的训练。谱归一化是…

YOLO目标检测——跌倒摔倒数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;公共安全监控、智能家居、工业安全等活动区域无监管情况下的人员摔倒事故数据集说明&#xff1a;YOLO目标检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富。使用lableimg标注软件标注&#xff0c;标注框质量高&#xff0c;含…

【Eclipse】取消按空格自动补全,以及出现没有src的解决办法

【Eclipse】设置自动提示 教程 根据上方链接&#xff0c;我们已经知道如何设置Eclipse的自动补全功能了&#xff0c;但是有时候敲变量名的时候按空格&#xff0c;本意是操作习惯&#xff0c;不需要自动补全&#xff0c;但是它却给我们自动补全了&#xff0c;这就造成了困扰&…

诚迈科技董事长王继平出席中国(太原)人工智能大会并发表演讲

10月14日—15日&#xff0c;2023中国&#xff08;太原&#xff09;人工智能大会在山西省太原市举办。诚迈科技在大会上全面展示了其在人工智能领域的一系列创新技术与解决方案&#xff0c;诚迈科技董事长、统信软件董事长王继平受邀出席产业数字化转型论坛并发表主题演讲&#…

面试58同城!面试官问我redis 雪崩、穿透、击穿怎么处理?

一、Redis 缓存雪崩 1.1 缓存雪崩的概念 缓存雪崩指的是在某个时间点&#xff0c;缓存中的大量数据同时失效&#xff0c;导致大量请求直接落到数据库上&#xff0c;造成数据库压力过大&#xff0c;甚至引发系统崩溃。 1.2 缓存雪崩发生的原因 缓存雪崩通常是由以下原因引起…

[已解决]llegal target for variable annotation

llegal target for variable annotation 问题 变量注释的非法目标 思路 复制时编码错误&#xff0c;自己敲一遍后正常运行 #** 将垂直知识加入prompt&#xff0c;以使其准确回答 **# prompt_templates { # "recommand":"用户说&#xff1a;__INPUT__ …

紫光展锐荣评“5G技术创新力企业”,5G赋能千行百业

近日&#xff0c;2023年第十七届中国通信产业榜隆重发布&#xff0c;紫光展锐凭借多年以来在通信和芯片技术上的积累&#xff0c;从众多参选者中脱颖而出&#xff0c;荣评“5G技术创新力企业”&#xff0c;并蝉联2023年通信产业榜“中国通信设备技术服务供应商100强”。 作为一…

5.1 加载矢量图层(ogr,gpx)

文章目录 前言加载矢量(vector)图层ogrShapefileQGis导入.shp文件代码导入 gpxQGis导入GPX文件代码导入 gpkgQGis导入GPKG文件代码导入 geojsonQGis导入GeoJson文件代码导入 gmlQGis导入GML代码导入 kml/kmzQGis导入Kml代码导入 dxf/dwgQGis导入dxf代码导入 CoverageQGis导入Co…

JMeter安装及环境配置

1. JMeter 介绍 Apache组织开发的基于Java的压力测试工具 100%纯Java开发、完全的可移植性 可以用于测试静态和动态资源 多协议—HTTP/FTP/socket/Java/数据库(JDBC) 完全多线程 高可扩展性 2. 安装jdk并配置jdk环境 因为jmeter运行依赖jdk环境&#xff0c;所以在安装j…

lvgl 页面管理器

lv_scr_mgr lvgl 界面管理器 适配 lvgl 8.3 降低界面之间的耦合使用较小的内存&#xff0c;界面切换后会自动释放内存内存泄漏检测 使用方法 在lv_scr_mgr_port.h 中创建一个枚举&#xff0c;用于界面ID为每个界面创建一个页面管理器句柄将界面句柄添加到 lv_scr_mgr_por…