前端面试之Proxy与Reflect
🌟 一、Proxy 与 Reflect 的核心概念
1. Proxy:代理拦截器
Proxy 用于创建对象的代理,拦截并自定义对象的基本操作(如属性读写、函数调用等)。
核心组成:
-
目标对象(Target):被代理的原始对象。
-
处理器对象(Handler):定义拦截行为的对象,包含一组捕获器(Trap)。
示例:基础拦截
const user = { name: "小明", age: 25 };
const proxy = new Proxy(user, {get(target, prop) {console.log(`读取属性:${prop}`);return target[prop];},set(target, prop, value) {console.log(`设置属性:${prop} = ${value}`);target[prop] = value;return true; // 表示设置成功}
});
console.log(proxy.name); // 输出:读取属性:name → "小明"
proxy.age = 30; // 输出:设置属性:age = 30
2. Reflect:反射操作器
Reflect 提供一组静态方法,用于执行对象的默认操作(如 get
、set
),与 Proxy 捕获器一一对应。
设计目的:
-
统一对象操作 API(替代
Object.defineProperty
等)。 -
与 Proxy 配合,确保拦截操作与默认行为一致。
示例:替代传统操作
// 传统方式
obj.name = "Jack";
// Reflect 方式
Reflect.set(obj, "name", "Jack");
⚙️ 二、Proxy 的 13 种捕获器详解
Proxy 支持 13 种捕获器,覆盖对象的所有基本操作:
捕获器 | 拦截的操作 | 返回值要求 |
---|---|---|
get | 读取属性 | 任意值 |
set | 设置属性 | 布尔值 |
has | in 操作符 | 布尔值 |
deleteProperty | delete 操作符 | 布尔值 |
apply | 函数调用 | 任意值 |
construct | new 操作符 | 对象 |
getPrototypeOf | Object.getPrototypeOf | 对象/null |
setPrototypeOf | Object.setPrototypeOf | 布尔值 |
isExtensible | Object.isExtensible | 布尔值 |
preventExtensions | Object.preventExtensions | 布尔值 |
getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor | 属性描述符/null |
defineProperty | Object.defineProperty | 布尔值 |
ownKeys | Object.keys/values/entries | 数组 |
完整代码示例(属性隐藏):
const sensitiveData = { id: "001", password: "secret"
};
const hiddenProxy = new Proxy(sensitiveData, {get(target, prop) {if (prop === "password") throw new Error("禁止访问密码!");return Reflect.get(...arguments);},ownKeys(target) {return Reflect.ownKeys(target).filter(key => key !== "password");}
});
console.log(hiddenProxy.id); // "001"
console.log(Object.keys(hiddenProxy)); // ["id"](隐藏 password)
// hiddenProxy.password → 抛出错误
🔧 三、Reflect 的 13 个静态方法
Reflect 方法与 Proxy 捕获器一一对应,用于执行默认操作:
Reflect.apply()
Reflect.construct()
Reflect.get()
Reflect.set()
Reflect.defineProperty()
Reflect.deleteProperty()
Reflect.has()
Reflect.ownKeys()
Reflect.isExtensible()
Reflect.preventExtensions()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.setPrototypeOf()
为何使用 Reflect?
-
行为一致性:在 Proxy 捕获器中调用
Reflect.set()
可确保与默认行为一致。 -
错误处理:返回布尔值(如
Reflect.set()
返回true/false
),避免try/catch
。
🛠️ 四、应用场景与实战代码
1. 数据验证与类型检查
通过 set
捕获器拦截属性赋值,结合 Reflect 执行操作:
const validatedUser = new Proxy({}, {set(target, prop, value) {if (prop === "age" && typeof value !== "number") {throw new TypeError("年龄必须是数字!");}return Reflect.set(target, prop, value);}
});
validatedUser.age = 30; // 成功
validatedUser.age = "30"; // 抛出 TypeError
2. 观察者模式(数据绑定)
监听对象变更并通知观察者:
const observers = [];
const data = { count: 0 };
const observable = new Proxy(data, {set(target, prop, value) {const success = Reflect.set(...arguments);if (success) observers.forEach(fn => fn(prop, value));return success;}
});
observers.push((key, val) => console.log(`${key} 更新为 ${val}`));
observable.count = 10; // 输出:"count 更新为 10"
3. 函数劫持与日志记录
拦截函数调用并添加日志:
function add(a, b) { return a + b; }
const loggedAdd = new Proxy(add, {apply(target, thisArg, args) {console.log(`调用函数:参数为 ${args}`);const result = Reflect.apply(...arguments);console.log(`返回结果:${result}`);return result;}
});
loggedAdd(2, 3); // 输出日志并返回 5
4. 环境补全(Polyfill)
动态补全缺失的全局对象(如浏览器环境):
const documentProxy = new Proxy({}, {get(target, prop) {if (prop === "querySelector") {return () => ({ textContent: "动态创建的节点" });}return Reflect.get(target, prop);}
});
console.log(documentProxy.querySelector("#test").textContent); // "动态创建的节点"
5. Symbol 属性处理
特殊处理 Symbol 类型的属性:
const obj = { [Symbol("id")]: "123" };
const proxy = new Proxy(obj, {get(target, prop) {if (typeof prop === "symbol") {console.log(`访问 Symbol 属性:${prop.toString()}`);}return Reflect.get(target, prop);}
});
proxy[Symbol("id")]; // 输出日志
🚀 五、在框架与工程中的应用
-
Vue 3 响应式系统
Vue 3 使用 Proxy 替代Object.defineProperty
,实现更高效的依赖追踪。 -
数据层抽象
代理虚拟对象实现惰性加载(如按需加载数据库条目)。 -
AOP 编程(面向切面)
通过 Proxy/Reflect 统一添加日志、权限校验等横切关注点。
🚀 六、性能考虑与最佳实践
6.1 Proxy的性能影响
虽然Proxy非常强大,但需要注意:
- 性能开销:Proxy操作比直接操作对象慢
- 不适合高频操作:避免在性能关键路径中使用复杂Proxy
- 现代引擎优化:现代JavaScript引擎已大幅优化Proxy性能
6.2 最佳实践
- 谨慎使用:只在真正需要拦截操作时使用Proxy
- 保持轻量:避免在陷阱中执行繁重操作
- 使用Reflect:始终使用Reflect执行默认行为
- 处理receiver:正确传递receiver参数以支持继承
- 避免无限递归:小心在陷阱中访问代理对象自身
// 错误示例:在get陷阱中访问代理属性导致无限递归
const handler = {get(target, key) {// 错误:访问proxy自身属性导致递归调用return this[key] || target[key];}
};// 正确做法
const handler = {get(target, key, receiver) {// 使用Reflect.get并传递receiverreturn Reflect.get(target, key, receiver);}
};
💎 总结
Proxy 与 Reflect 是 JavaScript 元编程的核心工具:
-
Proxy:作为“拦截网”,定制对象操作行为。
-
Reflect:作为“安全执行器”,确保操作符合语言规范。
两者结合可实现高级模式(如响应式系统、AOP),显著提升代码灵活性与可维护性。
Proxy和Reflect为JavaScript打开了元编程的大门,让我们能够以更优雅的方式解决复杂问题。通过创建可拦截基本操作的对象代理,我们可以实现高级功能如数据绑定、不可变对象、验证系统等。
虽然Proxy功能强大,但也要谨慎使用,避免不必要的性能开销和复杂性。当正确使用时,它们将成为你工具箱中不可或缺的利器。
元编程不是魔法,而是理解语言本身的能力。掌握Proxy和Reflect,你将成为JavaScript的架构师而不仅仅是使用者。
相关文章:
前端面试之Proxy与Reflect
🌟 一、Proxy 与 Reflect 的核心概念 1. Proxy:代理拦截器 Proxy 用于创建对象的代理,拦截并自定义对象的基本操作(如属性读写、函数调用等)。 核心组成: 目标对象(Targe…...
uniapp vue3 鸿蒙支持的 HTML5+接口
uniapp vue3 编译鸿蒙所支持的 HTML5接口 文档:https://www.html5plus.org/doc/zh_cn/runtime.html {"geolocation": {//获取当前设备位置信息"getCurrentPosition": function() {},//监听设备位置变化信息"watchPosition": functi…...

一张Billing项目的流程图
流程图 工作记录 2016-11-11 序号 工作 相关人员 1 修改Payment Posted的导出。 Claim List的页面加了导出。 Historical Job 加了Applied的显示和详细。 郝 识别引擎监控 Ps (iCDA LOG :剔除了160篇ASG_BLANK之后的结果): LOG_File 20161110.txt BLANK_CDA/ALL 45/10…...

理想树图书:以科技赋能教育,开启AI时代自主学习新范式
深耕教育沃土 构建全场景教辅产品矩阵 自2013年创立以来,理想树始终以教育匠心回应时代命题。在教辅行业这片竞争激烈的领域,由专业教育工作者组成的理想树图书始终秉持“知识互映”理念,经过十余年的精耕细作,精心打造了小学同步…...

【大模型02】Deepseek使用和prompt工程
文章目录 DeepSeekDeepseek 的创新MLA (低秩近似) MOE 混合专家混合精度框架总结DeepSeek-V3 与 DeepSeek R1 DeepSeek 私有化部署算例市场: autoDLVllM 使用Ollma复习 API 调用deepseek-r1Prompt 提示词工程Prompt 实战设置API Keycot 示例p…...
B端产品经理如何快速完成产品原型设计
B 端产品经理的原型设计需兼顾业务流程复杂度、功能逻辑性和操作效率,快速完成原型的核心在于结构化梳理需求、复用成熟组件、借助高效工具、聚焦核心场景。以下是具体方法和步骤: 一、明确需求优先级:先框架后细节 1. 梳理业务流程&#x…...
[Java实战]Spring Boot切面编程实现日志记录(三十六)
[Java实战]Spring Boot切面编程实现日志记录(三十六) 一、AOP日志记录核心原理 1.1 AOP技术体系 Spring AOP基于代理模式实现,关键组件: JoinPoint:程序执行点(方法调用/异常抛出)Pointcut:切点表达式(定义拦截规则)Advice:增强逻辑(前置/环绕/异常通知)Weaving:…...
Apache POI生成的pptx在office中打不开 兼容问题 wps中可以打卡问题 POI显示兼容问题
项目场景: 在java服务中使用了apache.poi后生成的pptx在wps中打开是没有问题,但在office中打开显示如下XXX内容问题,修复(R)等问题 我是用的依赖版本如下 <dependency><groupId>org.apache.poi</grou…...

大学大模型教学:基于NC数据的全球气象可视化解决方案
引言 气象数据通常以NetCDF(Network Common Data Form)格式存储,这是一种广泛应用于科学数据存储的二进制文件格式。在大学气象学及相关专业的教学中,掌握如何读取、处理和可视化NC数据是一项重要技能。本文将详细介绍基于Python的NC数据处理与可视化解决方案,包含完整的代…...
Python学习(2) ----- Python的数据类型及其集合操作
在 Python 中,一切皆对象,每个对象都有类型。下面是 Python 中的常见内置类型分类和示例: 🟡 1. 数字类型(Numeric Types) 类型说明示例int整数5, -42float浮点数3.14, -0.5complex复数1 2j a 10 …...
机器学习算法-决策树
今天我们用一个 「相亲决策」 的例子来讲解决策树算法,保证你轻松理解原理和实现! 🌳 决策树是什么? 决策树就像玩 「20个问题」猜谜游戏: 你心里想一个东西(比如「苹果」) 朋友通过一系列问题…...

MediaMtx开源项目学习
这个博客主要记录MediaMtx开源项目学习记录,主要包括下载、推流(摄像头,MP4)、MediaMtx如何使用api去添加推流,最后自定义播放器,播放推流后的视频流,自定义Video播放器博客地址 1 下载 MediaMTX MediaMTX 提供了预编译的二进制文件,您可以从其 GitHub 页面下载: Gi…...

Linux安装EFK日志分析系统
目标:能够实现采集指定路径日志到es,用kibana实现日志分析 单es节点集群规划: 主机名IP 地址组件a1192.168.1.111Kibana elasticsearcha2192.168.1.112Fluentda3192.168.1.103Fluentd 1、安装Elasticsearch 1.1添加 Elastic 仓库并安装 E…...

Linux(9)——进程(控制篇——下)
目录 三、进程等待 1)进程等待的必要性 2)获取子进程的status 3)进程的等待方法 wait方法 waitpid方法 多进程创建以及等待的代码模型 非阻塞的轮训检测 四、进程程序替换 1)替换原理 2)替换函数 3&…...

E. Melody 【CF1026 (Div. 2)】 (求欧拉路径之Hierholzer算法)
E. Melody 思路 将所有出现过的音量和音高看作一个点,一个声音看作一条边,连接起来。那么很容易知道要找的就是图上的一条欧拉路径(类似一笔画问题) 又已知存在欧拉路径的充要条件为:度数为奇数的点的个数为0或者2个…...
@Pushgateway 数据自动清理
文章目录 Pushgateway 数据自动清理一、Pushgateway 数据清理的必要性二、自动清理方案方案1:使用带TTL功能的Pushgateway分支版本方案2:使用Shell脚本定期清理方案3:结合Prometheus记录规则自动清理 三、最佳实践建议四、验证与维护五、示例…...

粽叶飘香时 山水有相逢
粽叶飘香时 山水有相逢 尊敬的广大客户们: 五月初五,艾叶幽香。值此端午佳节,衡益科技全体同仁向您致以最诚挚的祝福! 这一年我们如同协同竞渡的龙舟,在数字化转型的浪潮中默契配合。每一次技术对接、每轮方案优化&a…...

YC-8002型综合变配电监控自动化系统
一 .系统概述 YC-8002型综合变配电监控自动化系统是西安亚川电力科技有限公司为适应广大客户要求,总结多项低 压配电网络自动化工程实例的经验,基于先进的电子技术、计算机和网络通讯等技术自主研发的--套结合本公司网络配电产品的应用于低压配电领域的…...

react diff 算法
diff 算法作为 Virtual DOM 的加速器,其算法的改进优化是 React 整个界面渲染的基础和性能的保障,同时也是 React 源码中最神秘的,最不可思议的部分 diff 算法会帮助我们就算出 VirtualDOM 中真正变化的部分,并只针对该部分进行原…...

近期手上的一个基于Function Grap(类AWS的Lambda)小项目的改造引发的思考
函数式Function是云计算里最近几年流行起来的新的架构和模式,因为它不依赖云主机,非常轻量,按需使用,甚至是免费使用,特别适合哪种数据同步,数据转发,本身不需要保存数据的业务场景,…...
Obsidian 社区插件下载修复
Obsidian 社区插件下载修复 因为某些原因,在国内经常无法下载 Obsidian 的社区插件。这个项目的主要目的就是修复这种情况,让国内的用户也可以无障碍的下载社区插件。 上手指南 下载 obsidian-proxy-github.zip解压 obsidian-proxy-github.zip将解压的…...

VSCode的下载与安装(2025亲测有效)
目录 0 前言1 下载2 安装3 后记 0 前言 丫的,谁懂啊,尝试了各种办法不行的话,我就不得不拿出我的最后绝招了,卸载,重新安装,我经常要重新安装,所以自己写了一个博客,给自己…...

千库/六图素材下载工具
—————【下 载 地 址】——————— 【本章下载一】:https://pan.xunlei.com/s/VORW9TbxC9Lmz8gCynFrgdBzA1?pwdxiut# 【本章下载二】:https://pan.quark.cn/s/829e2a4085d3 【百款黑科技】:https://ucnygalh6wle.feishu.cn/wiki/…...
Ansible模块——Ansible的安装!
Ansible 安装 Ansible 有三种安装方式,源码安装、发行版安装和 Python 安装。 使用发行版安装或 Python 安装两种方式时,Ansible 的安装包有两个,区别如下: • ansible-core:一种极简语言和运行时包,包含…...

差分S参数-信号与电源完整性分析
差分S参数: 由于差分互连中使用差分信号传递信息,接收器最关心的是差分信号的质量,如果互连通道的S参数能直接反映出对差分信号的影响,对分析问题将方便得多。差分互连通道可以看成是一个四端口网络,激励源为单端信号,…...
扣子Coze飞书多维表插件-查询数据
search_record - 查询数据 请求参数 apptoken - 多维表的唯一标识服 可选参数: automatic_fields - 控制是否返回自动计算的字段, true 表示返回。 field_names - 字段名称,用于指定本次查询返回记录中包含的字段。 示例值:["字段1&…...
计算机模拟生物/化学反应有哪些软件?
以下是用于计算机模拟生物/化学反应的软件分类总结,涵盖量子化学、分子动力学、化学信息学及新兴混合方法等方向,结合其核心功能和应用场景进行整理: ⚛️ 一、量子化学计算软件 ChemiQ(本源量子) 类型:量子…...

PostIn V1.1.2版本发布,新增接口评审功能,提升接口质量与合理性
PostIn是一款国产开源免费的接口管理工具,包含项目管理、接口调试、接口文档设计、接口数据MOCK等模块,支持常见的HTTP协议、websocket协议。本周PostIn V1.1.0版本发布,新增接口评审、接口统计功能。 1、版本更新日志 新增 ➢ 接口评审&a…...
MySQL数据归档利器:pt-archiver原理剖析与实战指南
MySQL数据归档利器:pt-archiver原理剖析与实战指南 在MySQL数据库管理中,数据归档是一个永恒的话题——随着业务数据的不断增长,如何高效、安全地将历史数据从生产表迁移到归档表或文件,同时不影响在线业务,是每个DBA和开发者都需要面对的挑战。Percona Toolkit中的pt-ar…...

【论文阅读】User Diverse Preference Modeling by Multimodal Attentive Metric Learning
User Diverse Preference Modeling by Multimodal Attentive Metric Learning 题目翻译:基于多模态注意度量学习的用户不同偏好建模 摘要 提出一个**多模态注意力度量学习(MAML, Multimodal Attentive Metric Learning)**方法,…...