JavaScript 对象管家 Proxy

JavaScript 在 ES6 中,引入了一个新的对象类型 Proxy,它可以用来代理另一个对象,并可以在代理过程中拦截、覆盖和定制对象的操作。Proxy 对象封装另一个对象并充当中间人,其提供了一个捕捉器函数,可以在代理对象上拦截所有的操作,包括访问属性、赋值属性、函数调用等等。通过拦截这些操作,可以对代理对象进行定制和控制。

JavaScript 对象管家 Proxy 模式

在开始介绍 Proxy 对象前先了解 3 个术语:

  1. target 目标对象:要代理的对象或函数。
  2. handler 处理程序:对代理的对象或函数执行某些操作的函数。
  3. traps 捕捉器:这些是一些用于处理目标的函数。单击此处阅读有关陷阱的更多信息。

语法

Proxy 对象的基本语法如下:

new Proxy(target, handler);

其中,target 是被代理的目标对象,handler 是一个对象,它包含了一些捕捉器函数,用来拦截代理对象的操作。

下面是一些常见的拦截操作和对应的捕捉器函数:

对象方法
  1. getPrototypeOf()Object.getPrototypeOf 方法的捕捉器。
  2. setPrototypeOf()Object.setPrototypeOf 方法的捕捉器。
  3. isExtensible()Object.isExtensible 方法的捕捉器。
  4. preventExtensions()Object.preventExtensions 方法的捕捉器。
  5. getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor 方法的捕捉器。
  6. handler.defineProperty()Object.defineProperty 方法的捕捉器。
属性获取器/设置器
  1. get(target, propKey, receiver):拦截对象的读取属性操作,返回属性值。
  2. set(target, propKey, value, receiver):拦截对象的设置属性操作,返回一个布尔值表示是否设置成功。
  3. has(target, propKey):拦截对象的 in 操作符,返回一个布尔值表示对象是否包含该属性。
  4. deleteProperty(target, propKey):拦截对象的 delete 操作符,返回一个布尔值表示是否删除成功。
  5. ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器
函数方法

如果目标对象是一个函数,可以使用下面 2 个捕捉器。

  1. apply(target, thisArg, args):拦截函数的调用操作,返回调用结果。
  2. construct(target, args, newTarget):拦截 new 操作符,返回一个对象。

Proxy 在目标对象周围创建一个不可检测的屏障,将所有操作重定向到处理程序对象。如果发送一个空的 handler ,代理只是原始对象的一个空包装器。

const author = {name: "Quintion",age: 36,
};const proxyAuthor = new Proxy(author, {});console.log(author.name); // Quintion
console.log(proxyAuthor.name); // Quintion

为了赋予代理意义,需要向处理程序添加一些操作方法。

捕捉器

每当与一个对象交互时,都在调用一个内部方法。代理允许使用捕捉器拦截给定内部方法的执行。

因此,当运行 author.name 时,告诉 JavaScript 引擎调用内部 [[GET]] 方法来检索 name 属性。当运行 proxyAuthor.name 时,get 捕捉器会调用处理程序中定义的 get() 函数来执行,然后再将调用发送到原始对象。

Proxy捕捉器工作方式

get

get() 方法有两个必需的参数:

  • target — 传递给代理的对象。
  • property — 访问的属性的名称。

要自定义代理,在处理程序对象上定义函数。下面定义了 get 方法来记录访问:

const handler = {get(target, property) {console.log(`捕捉器 GET:${property}`);return target[property];},
};

为了让调用通过,捕捉器 get 返回 target[property]。使用方式如下:

const author = {name: "Quintion",age: 36,
};const handler = {get(target, property) {console.log(`捕捉器 GET[${property}]`);return target[property];},
};const proxyAuthor = new Proxy(author, handler);console.log(proxyAuthor.name);

执行后,将打印以下内容:

捕捉器 GET[name]
Quintion
set

set 捕捉器用于给目标对象进行赋值操作,返回值是一个布尔值。set 捕捉器需要的参数如下:

  • target — 传递给代理的对象。
  • property — 将被设置的属性名或 Symbol。
  • value — 新的属性值
  • receiver — 最初被调用的对象。

下面通过 set 捕捉器验证年龄值的输入:

const handler = {set(target, property, value) {if (property === "age" && typeof value !== "number") {throw new TypeError("年龄必须是一个数字");}target[property] = value;return true;},
};

下面尝试将错误的类型值赋值给 age ,则会抛出错误:

const proxyAuthor = new Proxy(author, handler);proxyAuthor.age = "young";
// 执行后抛出异常:throw new TypeError("年龄必须是一个数字");

set() 方法应该返回一个布尔值 true 用来表示赋值成功。 在严格模式下运行,并且返回一个假值或什么都不返回,则会抛出错误。

除了拦截对属性的读取和修改,Proxy 总共可以拦截 13 种操作。

应用场景

通过 Proxy 对象的特征,可以将其使用在下面这些场合:

验证和过滤

代理Proxy 用于拦截和验证对对象属性的访问。如,可以创建一个代理来检查用户输入的数据是否符合预期的格式,并拒绝不正确的数据。就如下面 age 属性赋值判断

缓存

代理Proxy 用于缓存对象的操作结果,以避免重复计算。如,可以创建一个代理来拦截对象的某些方法,并将结果存储在缓存中,以便将来使用。

下面是一个基于 Proxy 的缓存库的示例:

class Cache {constructor() {this.cache = new Map();this.proxy = new Proxy(this, {get(target, property) {if (property === "get") {return (key) => {return target.cache.get(key);};}if (property === "set") {return (key, value) => {target.cache.set(key, value);};}if (property === "has") {return (key) => {return target.cache.has(key);};}if (property === "delete") {return (key) => {return target.cache.delete(key);};}},});}
}

在上面的代码中,定义了一个 Cache 类,该类中包含一个内部的 Map 对象用于存储缓存数据,并且定义了一个 proxy 对象作为该类的代理。

在 proxy 对象的 get 方法中,根据传入的属性名返回相应的方法。如果属性名为 get,则返回一个可以获取缓存值的方法;如果属性名为 set,则返回一个可以设置缓存值的方法;如果属性名为 has,则返回一个可以判断是否存在缓存值的方法;如果属性名为 delete,则返回一个可以删除缓存值的方法。

下面是一个使用该缓存库的示例:

const cacheHelper = new Cache();cacheHelper.set("foo", "bar");
console.log(cacheHelper.get("foo")); // "bar"
console.log(cacheHelper.has("foo")); // truecacheHelper.delete("foo");
console.log(cacheHelper.get("foo")); // undefined
console.log(cacheHelper.has("foo")); // false

在上面的代码中,创建了一个 Cache 对象,并调用其 set 方法设置缓存值,然后调用其 get 方法获取缓存值,并调用其 has 方法判断缓存值是否存在,最后调用其 delete 方法删除缓存值。

监听属性变化

代理Proxy用于监视对象属性的变化,并在属性发生变化时触发其他操作。如,创建一个代理来监视对象属性的变化,并在属性发生变化时更新页面上的元素。

防止误操作

代理Proxy用于防止误操作,如,创建一个代理来拦截对象的某些方法,并在方法调用时检查一些条件,以确保方法只在正确的上下文中调用。

虚拟化

代理Proxy可以用于创建虚拟化对象。如,创建一个代理对象,用于代替某个对象的真实实现,并且在实际对象执行之前,对其进行修改或拦截。

总结

上面介绍了如何使用代理Proxy对象来监视对象,通过使用处理程序对象中的捕捉器方法向它们添加自定义行为,提供更高级的对象操作和控制功能,从而增强代码的可读性和可维护性。

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

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

相关文章

基于Zabbix 5.0 实现windows服务器上应用程序和主机端口的状态监控

基于Zabbix 5.0 实现windows服务器上应用程序和主机端口的状态监控 背景 用python开发的应用程序在服务器上运行,有时候会出现程序自动退出却收不到告警的情况 环境 zabbix服务器:Centos7 64位 Windows服务器: Windows 10 64位 软件 zabbix_server:zabbix5.0 zabbix_…

680.验证回文串II-力扣

680.验证回文串II-力扣 给你一个字符串 s,最多可以从中删除一个字符。 请你判断 s 是否能成为回文字符串:如果能,返回 true ;否则,返回 false。 示例1: 输入:s “aba” 输出:true示…

如何制作一个微信小程序商城?

在这个数字化飞速发展的时代,微信小程序商城以其独特的便捷性和高效的用户连接能力,成为了电商领域的一颗新星。对于那些渴望在微信平台上开展业务的商家和企业来说,微信小程序商城不仅是一种新的尝试,更是一个充满无限可能的商机…

2024年文化传播、交流与考古学国际会议 (CCEA 2024)

2024年文化传播、交流与考古学国际会议 (CCEA 2024) 2024 International Conference on Cultural Communication, Exchange, and Archaeology 【会议简介】 2024年文化传播、交流与考古学国际会议即将在千年古都西安盛大召开。本次会议将汇聚全球文化、传播、考古等领域的专家…

每日一题(leetcode2952):添加硬币最小数量 初识贪心算法

这道题如果整体去思考,情况会比较复杂。因此我们考虑使用贪心算法。 1 我们可以假定一个X,认为[1,X-1]区间的金额都可以取到,不断去扩张X直到大于target。(这里为什么要用[1,X-1]而不是[1,X],总的来说是方便,潜在思想…

浏览器工作原理与实践--async/await:使用同步的方式去写异步代码

在上篇文章中,我们介绍了怎么使用Promise来实现回调操作,使用Promise能很好地解决回调地狱的问题,但是这种方式充满了Promise的then()方法,如果处理流程比较复杂的话,那么整段代码将充斥着then,语义化不明显…

使用Bitmaps位图实现Redis签到

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 Redis提供了Bitmaps这个“数据类型”可以实现对位的操作: (1) Bitmaps…

基于Weibull、Beta、Normal分布的风、光、负荷场景生成及K-means场景削减方法

目录 一、主要内容: 二、代码运行效果: 三、Weibull分布与风机风速: 四、Beta分布与光伏辐照度: 五、Normal分布与电负荷: 六、K-means聚类算法: 七、完整代码数据下载: 一、主要内容&am…

【数论】莫比乌斯反演(欧拉反演)进阶-杜教筛

文章目录 前言 回忆 题集12 杜教筛例题 前言 这里需要对莫反有一些基础。 不会的可以点这里 回忆 f ( n ) ∑ d ∣ n g ( d ) → g ( n ) ∑ d ∣ n f ( d ) μ ( n d ) f(n)\sum_{d|n}g(d)\rightarrow g(n)\sum_{d|n}f(d)\mu(\frac{n}{d}) f(n)∑d∣n​g(d)→g(n)∑d∣n​…

Windows如何优雅的运行ROS2/linux

Windows如何优雅的运行ROS2/linux 前言 在ROS/ROS2开发过程中,大家普遍使用到的分布式开发方法都是基于虚拟机/双系统进行,本质上是希望基于Ubuntu良好的生态环境进行,但是两种方式各有各自的好处,也有各自的弊端,例…

docker 部署 nali 开源 IP 地理信息归属查询软件

前言 早前用到一个小巧开源的 IP 归属地查询软件,官方提供了 Dockerfile,使用了一段时间觉得还不错,非常简单便捷。 部署 docker 启动 由于该项目会在首次启动自动下载 IP 数据库,所以最好通过挂载目录的方式,将数据库目录挂在到本地,避免…

Java零基础入门到精通_Day 4

方法的重载 就是同一个类中的相同方法名的多个方法,但是他们的参数不同,类型不同或者参数个数不同。 (与返回值无关) package Base_One;public class Base_005 {public static void main(String[] args) {// Main method logic …

经久耐用耐强腐蚀PFA材质气体洗涤瓶全氟烷氧基树脂尾气吸收瓶

PFA洗气瓶是一种常用于净化和干燥各种气体的实验室器皿,以去除其中的水分、油脂、颗粒物等杂质,从而使需要用到的气体满足实验要求。 PFA气体吸收瓶 PFA洗气瓶的工作原理: 主要是通过液体吸收、溶解或发生化学反应来去除气体中的杂质。在洗气…

Python基础之pandas:文件读取与数据处理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、文件读取1.以pd.read_csv()为例:2.数据查看 二、数据离散化、排序1.pd.cut()离散化,以按范围加标签为例2. pd.qcut()实现离散化3.排序4.…

新质生产力崛起,运营商前端运营如何跃升

“新质生产力”一个当前的热搜高频词,今年还被首次写进政府工作报告,是2024年十大工作任务的首位。那么什么是“新质生产力”?它对于我们的生活、学习、工作及未来发展有什么影响呢?今天小宝就抛砖引玉来讲一讲“新质生产力”对于…

整顿编剧市场:程序员提交测试流程的最佳实践

讲动人的故事,写懂人的代码 最近,一部去年推出的国产电视剧在IT圈子里引起了轰动。 引起关注的原因,并非剧中程序员的外形出众,而是她提交代码测试的方式——将写有代码的纸张放入文件夹,然后递给了对面的测试人员。如图1所示。 图1 程序员将写有代码的纸张放入文件夹,并…

信创(统信)系统上的软件安装及软件使用手册

一.各软件的安装文档 1.达梦数据库在统信系统上的安装 官方手册:https://eco.dameng.com/document/dm/zh-cn/start/install-dm-linux-prepare.html 1.1下载安装包 官网:https://www.dameng.com/list_103.html 点击”服务与合作”--> “下载中心” 这里选择对应的cpu和操作…

Git 核心知识

2024年4月2日更新 Git 安装 官网下载,Git 选择合适的版本,无脑下一步即可。 安装成功之后,鼠标右键任意的文件夹,会出现 Git GUI 的选项,即安装成功 安装注意事项 安装前,检查环境变量 , 如…

程序的编译、链接过程分析(简洁浓缩版)!

《嵌入式工程师自我修养/C语言》系列——程序的编译、链接过程分析(简洁浓缩版)! 一、程序的编译1.1 预编译指令 pragma1.2 编译过程概述1.3 符号表和重定位表 二、程序的链接2.1 分段组装2.2 符号决议2.2.1 强符号与弱符号2.2.2 GNU编译器的…

在线考试系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)高校远程网络考试,课程信息,在线考试,试题管理,习题管理课程信息,教师管理,学生管理

本项目包含可运行源码数据库LW,文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…