之前写了一篇介绍 Object.defineProperty的,提到proxy,二者有一些共性,也都是前端框架Vue的核心机制,所以再写一篇介绍一下proxy的基础原理和使用。

在 JavaScript 中,Proxy 是 ES6 引入的一个元编程特性,用于创建对象的代理,从而可以拦截并自定义对该对象的基本操作(如属性访问、赋值、枚举、函数调用等)。与 Object.defineProperty() 相比,Proxy 提供了更强大、更全面的元编程能力。

核心作用

  1. 拦截对象操作
    通过定义拦截器(trap),可以捕获并自定义对象的各种操作(如属性读取、赋值、函数调用等)。
  2. 实现元编程
    允许修改语言的底层行为,例如自定义属性访问权限、实现数据验证、模拟私有属性等。
  3. 创建响应式系统
    Object.defineProperty() 更适合实现响应式数据绑定(如 Vue.js 3.x),因为它能拦截更广泛的操作且支持深层监听。

基本语法

const proxy = new Proxy(target, handler);
  • target:需要被代理的对象。
  • handler:一个对象,包含拦截各种操作的陷阱函数(trap)。

常用拦截器(Traps)

拦截器触发时机
get(target, prop, receiver)读取属性时触发
set(target, prop, value, receiver)设置属性值时触发
has(target, prop)判断属性是否存在(in 操作符)
deleteProperty(target, prop)删除属性时触发
ownKeys(target)获取对象所有属性键(如 Object.keys()
apply(target, thisArg, args)代理函数调用时触发
construct(target, args, newTarget)代理构造函数调用时触发(new 操作符)

用法示例

1. 基本拦截:属性读取和赋值
const person = { name: 'John', age: 30 };const proxy = new Proxy(person, {// 拦截属性读取get(target, prop) {console.log(`读取属性 ${prop}`);return target[prop];},// 拦截属性赋值set(target, prop, value) {console.log(`设置属性 ${prop}${value}`);if (prop === 'age' && typeof value !== 'number') {throw new Error('年龄必须是数字');}target[prop] = value;return true; // 表示赋值成功}
});console.log(proxy.name); // 读取属性 name → John
proxy.age = 31;          // 设置属性 age 为 31
proxy.age = 'thirty';    // Error: 年龄必须是数字
2. 实现数据验证
const validator = {set(target, prop, value) {if (prop === 'age' && value < 0) {throw new Error('年龄不能为负数');}target[prop] = value;return true;}
};const person = new Proxy({ age: 30 }, validator);
person.age = -5; // Error: 年龄不能为负数
3. 实现私有属性
const privateData = new WeakMap();const createPerson = (name, age) => {privateData.set({ name, age }, { salary: 5000 });return new Proxy({ name, age }, {get(target, prop) {if (privateData.has(target) && prop === 'salary') {return privateData.get(target)[prop];}return target[prop];}});
};const person = createPerson('John', 30);
console.log(person.name);  // John
console.log(person.salary); // undefined(外部无法访问)
4. 函数调用拦截
const sum = (a, b) => a + b;const proxy = new Proxy(sum, {apply(target, thisArg, args) {console.log(`调用函数,参数:${args}`);return target(...args) * 2; // 结果翻倍}
});console.log(proxy(2, 3)); // 调用函数,参数:2,3 → 10

Object.defineProperty() 的对比

特性Object.defineProperty()Proxy
监听范围只能监听对象的已有属性(需逐个定义)可以监听整个对象(包括新增属性)
深层监听需要递归处理嵌套对象可以通过递归代理实现深层监听
数组支持对数组的监听有限(需特殊处理)全面支持数组操作(如 pushpop
元编程能力仅能控制单个属性的行为可以拦截多种操作(如 indelete、函数调用等)
性能对于大量属性的对象,性能略高对于频繁操作的场景,性能略低
兼容性ES5(支持 IE9+)ES6(不支持 IE)

应用场景

  1. 响应式系统
    Vue.js 3.x 使用 Proxy 替代 Object.defineProperty() 实现响应式数据:

    const reactive = (target) => {return new Proxy(target, {get(target, prop) {// 依赖收集return target[prop];},set(target, prop, value) {target[prop] = value;// 触发更新updateDOM();return true;}});
    };
    
  2. 数据验证与转换
    在属性赋值时自动验证或转换数据:

    const withValidation = (target, validators) => {return new Proxy(target, {set(target, prop, value) {if (validators[prop] && !validators[prop](value)) {throw new Error(`Invalid value for ${prop}`);}target[prop] = value;return true;}});
    };const person = withValidation({ name: '', age: 0 },{ age: (v) => typeof v === 'number' && v > 0 }
    );
    
  3. 日志记录与性能监控
    拦截对象操作并记录日志:

    const withLogging = (target) => {return new Proxy(target, {get(target, prop) {console.log(`Getting ${prop}`);return target[prop];},set(target, prop, value) {console.log(`Setting ${prop} to ${value}`);target[prop] = value;return true;}});
    };
    

注意事项

  1. 兼容性Proxy 是 ES6 特性,不支持 IE。
  2. 性能开销Proxy 的拦截操作比直接访问对象属性有更高的性能开销,不适合高性能场景。
  3. this 指向:在 Proxy 的陷阱函数中,this 指向 handler 对象,而非 target 对象。
  4. 反射 API:通常与 Reflect 对象配合使用,以保持原生行为:
    const proxy = new Proxy(target, {get(target, prop, receiver) {return Reflect.get(target, prop, receiver);}
    });
    

总结

  • Object.defineProperty():适合简单场景(如单个对象的属性监听),兼容性好,但功能有限。
  • Proxy:适合复杂场景(如框架开发、全面的数据拦截),功能强大,但有兼容性和性能限制。

选择哪种方式取决于具体需求:若需要全面控制对象操作且不考虑 IE 兼容性,Proxy 是更好的选择;若需要兼容旧浏览器或仅需简单属性监听,可使用 Object.defineProperty()

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

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

相关文章

HTTP性能优化实战技术

HTTP性能优化实战技术文章大纲 理解HTTP性能优化的核心指标 关键指标&#xff1a;延迟、吞吐量、TTFB&#xff08;Time To First Byte&#xff09;、页面加载时间影响性能的因素&#xff1a;网络延迟、服务器响应时间、资源大小、协议效率 减少HTTP请求数量 合并资源文件&#…

ubuntu(22.04)系统上安装 MuJoCo

在 Linux 系统上安装 MuJoCo 的完整步骤如下&#xff1a; ​​1. 下载 MuJoCo​​ 访问 MuJoCo 官方 GitHub下载最新 Linux 版本&#xff08;如 mujoco-3.3.4-linux-x86_64.tar.gz&#xff09;获取对应的 SHA256 校验值&#xff08;在发布页面可以找到,&#xff0c;文件名后面…

理解大模型的对话和检索能力

RAG和联网搜索均通过“检索生成”模式扩展模型能力&#xff0c;但RAG基于内部知识库&#xff08;如企业文档&#xff09;&#xff0c;适合专业领域问答&#xff1b;联网搜索实时检索互联网&#xff0c;解决时效性问题&#xff08;如新闻、股价&#xff09;。RAG响应快且可控&am…

跟着Carl学算法--回溯【2】

IP复原&#xff08;难&#xff09; 力扣链接&#xff1a;IP复原 题目&#xff1a;有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201"…

PyTorch生成式人工智能(17)——变分自编码器详解与实现

PyTorch生成式人工智能(17)——变分自编码器详解与实现 0. 前言1. 潜空间运算2. 变分自编码器2.1 自编码器与变分自编码器对比2.2 模型训练流程3. 构建变分自编码器3.1 模型构建3.2 模型训练3.3 生成图像4. 向量运算小结系列链接0. 前言 虽然自编码器 (AutoEncoder, AE) 在重…

SpringMVC2

一、接口声明的稳定性- 接口声明不能轻易变&#xff1a;接口是前后端、服务间通信的约定。要是接口的 URL、请求方法、参数、返回值变了&#xff0c;调用方&#xff08;比如前端、其他服务&#xff09;就得跟着改&#xff0c;容易出问题。所以设计接口要谨慎&#xff0c;别老变…

LVS集群实践

一、LVS概念VS: Virtual Sever &#xff08;调度器&#xff09;RS: Real Sever &#xff08;资源主机&#xff09;CIP: Client IP &#xff08;用户IP&#xff09;VIP: Virtual sever IP &#xff08;VS外网的IP&#xff0c;客户访问的IP&#xff09;DIP: Director IP &#xf…

使用Django框架构建Python Web应用

前言Django个高级Python Web框架&#xff0c;遵循MTV&#xff08;Model-Template-View&#xff09;设计模式&#xff1a;模型(Model)&#xff1a;数据层&#xff0c;定义数据结构模板(Template)&#xff1a;表现层&#xff0c;处理用户界面视图(View)&#xff1a;业务逻辑层&am…

[AI-video] 数据模型与架构 | LLM集成

第五章&#xff1a;数据模型与架构 欢迎来到第五章&#xff01; 在前几章中&#xff0c;我们学习了网页用户界面&#xff08;UI&#xff09;&#xff08;控制面板&#xff09;、应用配置&#xff08;系统参数设置&#xff09;、任务编排&#xff08;视频生成流程的总调度&…

HTTP 性能优化实战:突破高并发瓶颈的工业级方案

在互联网高并发场景中&#xff0c;HTTP 性能表现直接决定系统生死。当每秒请求量突破十万级甚至百万级时&#xff0c;哪怕 100 毫秒的延迟都会引发用户流失、交易失败等连锁反应。本文基于五大行业实战案例&#xff0c;拆解 HTTP 性能瓶颈的底层逻辑&#xff0c;输出可直接落地…

Xsens人形机器人拟人动作AI训练,提升机器人工作精度与效率

随着人工智能与机器人技术的深度融合&#xff0c;人形机器人正从实验室走向工业制造、医疗护理、公共服务等真实场景。然而&#xff0c;要让机器人真正"像人类一样工作"&#xff0c;其动作的流畅性、精准度与环境适应性仍是技术突破的关键。Xsens动作捕捉系统通过创新…

IIS网站间歇性打不开暴力解决方法

背景 网站使用 Asp.NET 框架开发&#xff0c;使用 SQL Server 2012 IIS 8.5 运行。开发上线以后&#xff0c;经常出现网站间歇性打不开&#xff0c;但是重启 IIS 就可以正常访问。 问题排查过程 打开日志记录 观察 CPU&#xff0c;内存&#xff0c;带宽流量等占用正常&#xf…

JavaScript 动态访问嵌套对象属性问题记录

问题描述不能解析 2 层 只能解析一层在 Vue 项目中&#xff0c;尝试通过动态路径&#xff08;如 otherInfo.businessPlacePhotoUrlLabel&#xff09;访问或修改嵌套对象属性时&#xff0c;发现 this[a.b.c] 无法正确解析&#xff0c;导致返回 undefined。错误示例removeImg(val…

7.17 滑动窗口 | assign

lc3015.法1&#xff1a;暴力bfs&#xff0c;数据范围only 100&#xff0c;可以过法2&#xff1a;加入了x,y&#xff0c;可以思考加入的x,y影响了什么呢? 通过数学找规律class Solution { public:vector<int> countOfPairs(int n, int x, int y) {vector<int> ret(…

预训练模型:大规模数据预学习范式——定义、原理与演进逻辑

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 以下基于权威教材、学术论文及行业技术报告&#xff0c;对“预训练模型…

【kubernetes】--安全认证机制

文章目录安全认证1. **身份认证&#xff08;Authentication&#xff09;**2. **授权&#xff08;Authorization&#xff09;**3. **准入控制&#xff08;Admission Control&#xff09;**4. **机密信息管理**5. **其他安全实践**安全认证 Kubernetes 的安全机制覆盖了从身份验…

扣子工作流详解

《扣子开发AI Agent智能体应用&#xff08;人工智能技术丛书&#xff09;》(宋立桓&#xff0c;王东健&#xff0c;陈铭毅&#xff0c;程东升)【摘要 书评 试读】- 京东图书 《扣子开发AI Agent智能体应用》案例重现 开发agent智能体的书籍-CSDN博客 工作流是指一系列相互关联…

【一文解决】块级元素,行内元素,行内块元素

块级元素&#xff0c;行内元素&#xff0c;行内块元素&#xff01;盒模型1.标准盒模型&#xff08;box-sizing: content-box&#xff09;2.IE 盒模型&#xff08;box-sizing: border-box&#xff09;&#xff01;margin & padding1.margin、padding是什么2. 应用一、块级元…

在 Spring Boot 中使用 MyBatis 的 XML 文件编写 SQL 语句详解

前言 在现代 Java Web 开发中&#xff0c;Spring Boot 和 MyBatis 是两个非常流行的技术框架。它们的结合使得数据库操作变得更加简洁和高效。本文将详细介绍如何在 Spring Boot 项目中使用 MyBatis 的 XML 文件来编写 SQL 语句&#xff0c;包括配置、代码结构、SQL 编写技巧以…

字段级权限控制场景中,RBAC与ABAC的性能差异

RBAC(基于角色访问控制)与ABAC(基于属性访问控制)的性能差异主要体现在​​计算复杂度、策略灵活性、扩展性​​和​​资源消耗​​等方面。以下是具体对比分析: ​​一、性能对比维度​​ ​​维度​​​​RBAC​​​​ABAC​​​​计算复杂度​​低(预计算角色权限映射…