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.hqwc.cn/news/588533.html

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

相关文章

36.基于SpringBoot + Vue实现的前后端分离-高校汉服租赁网站系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统,采用SpringBoot Vue框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得基于SpringBoot Vue技术的高校汉服租赁网站系统设计与实现管理…

基于java+springboot+vue实现的医院门诊在线挂号系统(文末源码+Lw)23-222

摘 要 伴随着信息技术与互联网技术的不断发展,校园也进到了一个新的信息化时代,传统管理技术性没法高效率、容易地管理医院门诊在线挂号信息内容。为了实现时代的发展必须,提升医院门诊在线挂号高效率,各种各样医院门诊在线挂号…

高效学习方法:冥想背诵,看一句念一句,再每个词分析位置及语法等合理性,忘记哪个词再看猜下为什么会忘,跟自己的表达哪里不一样。

原则:易学则易行,则效果最好。《易经》 你提到的这种学习方法结合了多种记忆和理解技巧,可以帮助提高学习效率。下面是对这种方法的一个详细解释和一些建议: 冥想背诵:通过冥想来集中注意力,可以帮助你在没…

AI智能校色解决方案,专业级画质提升

由于拍摄环境、设备性能以及编辑经验等多种因素的影响,视频画质往往难以达到理想状态。这时,一款高效、智能的校色解决方案就显得尤为重要。美摄科技凭借深厚的图像处理技术和AI算法研发实力,推出了全新的AI智能校色解决方案,助力…

SAD法(附python实现)和Siamese神经网络计算图像的视差图

1 视差图 视差图:以左视图视差图为例,在像素位置p的视差值等于该像素在右图上的匹配点的列坐标减去其在左图上的列坐标 视差图和深度图: z f b d z \frac{fb}{d} zdfb​ 其中 d d d 是视差, f f f 是焦距, b b…

C语言第三十九弹---预处理(上)

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 预处理 1、预定义符号 2、#define定义常量 3、#define定义宏 4、带有副作用的宏参数 5、宏替换的规则 6、宏和函数的对比 总结 在C语言中,预处…

臻奶惠无人售货机:新零售时代的便捷消费革命

臻奶惠无人售货机:新零售时代的便捷消费革命 在新零售的浪潮中,智能无人售货机作为一个创新的消费模式,已经成为距离消费者最近的便捷购物点之一。这种模式不仅能够满足居民对消费升级的需求,还能通过建立多样化和多层次的消费体…

【御控物联】JavaScript JSON结构转换(12):对象To数组——键值互换属性重组

文章目录 一、JSON结构转换是什么?二、核心构件之转换映射三、案例之《JSON对象 To JSON数组》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么? JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换…

酒吧酒馆微信小程序设计基于Java,SpringBoot,Vue和UniApp

摘要 该设计目标是创建一个集成了Java, SpringBoot, Vue和UniApp技术的酒吧微信小程序,为用户提供一个功能全面、操作便捷的服务体验。通过利用SpringBoot的高效微服务架构,后端能够快速处理用户请求,实现酒品浏览、订单管理等核心功能&…

Centos7环境下安装MySQL8详细教程

1、下载mysql安装包 2、检查是否安装过mysql ps:因为以前用yum安装过,所以先用yum卸载。如果不是此方式或者没安装过则跳过 [rootlocalhost ~]# yum remove mysql 已加载插件:fastestmirror 参数 mysql 没有匹配 不删除任何软件包 查看是否有mysql依赖 …

【SQL Server】1. 认识+使用

1. 创建数据库的默认存储路径 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft SQL Server 2008 R2 当我们选择删除数据库时,对应路径下的文件也就删除了 2. 导入导出数据工具的路径 3. 注册数据库遇到的问题 ??? 目前的问题就是服务器新建…

【C语言基础】:自定义类型(一)--> 结构体

文章目录 一、内置类型与自定义类型1.1 内置类型(基本数据类型)1.2 自定义类型 二、结构体2.1 结构体的声明2.2 结构体变量的创建和初始化2.3 结构体的特殊声明2.4 结构体的自引用 三、结构体内存对齐3.1 对齐规则3.2 为什么存在内存对齐3.3 修改默认对齐…