JavaScript系列(75)--代理模式专题

JavaScript代理模式专题 🎭

JavaScript的Proxy提供了强大的对象代理能力,能够拦截和自定义对象的基本操作。本文将深入探讨Proxy的各种模式、应用场景和最佳实践。

代理基础 🌟

💡 小知识:代理模式允许我们创建一个对象的代理,从而可以控制对这个对象的访问。JavaScript的Proxy API提供了13种基本操作的拦截器(trap),使我们能够自定义对象的行为。

// 基础代理操作
const target = { name: '张三', age: 25 };
const handler = {get(target, property) {console.log(`访问属性: ${property}`);return target[property];},set(target, property, value) {console.log(`设置属性: ${property} = ${value}`);target[property] = value;return true;}
};const proxy = new Proxy(target, handler);
console.log(proxy.name);  // 输出: 访问属性: name 然后是 "张三"
proxy.age = 26;          // 输出: 设置属性: age = 26

Proxy拦截器详解 📋

1. 基本拦截器

class BasicTraps {static demonstrateBasicTraps() {const handler = {// 属性读取拦截get(target, prop, receiver) {return Reflect.get(target, prop, receiver);},// 属性设置拦截set(target, prop, value, receiver) {return Reflect.set(target, prop, value, receiver);},// 属性删除拦截deleteProperty(target, prop) {return Reflect.deleteProperty(target, prop);},// 属性存在性检查拦截has(target, prop) {return Reflect.has(target, prop);}};return new Proxy({}, handler);}
}

2. 高级拦截器

class AdvancedTraps {static demonstrateAdvancedTraps() {const handler = {// 对象属性枚举拦截ownKeys(target) {return Reflect.ownKeys(target);},// 属性描述符获取拦截getOwnPropertyDescriptor(target, prop) {return Reflect.getOwnPropertyDescriptor(target, prop);},// 原型获取拦截getPrototypeOf(target) {return Reflect.getPrototypeOf(target);},// 原型设置拦截setPrototypeOf(target, proto) {return Reflect.setPrototypeOf(target, proto);}};return new Proxy({}, handler);}
}

3. 函数和构造器拦截

class FunctionTraps {static demonstrateFunctionTraps() {function target(a, b) {return a + b;}const handler = {// 函数调用拦截apply(target, thisArg, args) {console.log(`调用函数,参数:${args}`);return Reflect.apply(target, thisArg, args);},// 构造函数调用拦截construct(target, args, newTarget) {console.log(`构造函数调用,参数:${args}`);return Reflect.construct(target, args, newTarget);}};return new Proxy(target, handler);}
}

常用代理模式 💼

1. 验证代理

class ValidationProxy {static createValidator(validationRules) {return new Proxy({}, {set(target, property, value) {if (validationRules[property]) {const [isValid, message] = validationRules[property](value);if (!isValid) {throw new Error(`验证失败: ${property} - ${message}`);}}return Reflect.set(target, property, value);}});}
}// 使用示例
const userValidator = ValidationProxy.createValidator({age: (value) => [Number.isInteger(value) && value >= 0 && value <= 150,'年龄必须是0-150之间的整数'],email: (value) => [/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),'邮箱格式不正确']
});

2. 日志代理

class LoggingProxy {static createLogger(target, logCallback = console.log) {return new Proxy(target, {get(target, property) {logCallback(`获取属性: ${property}`);return Reflect.get(target, property);},set(target, property, value) {logCallback(`设置属性: ${property} = ${value}`);return Reflect.set(target, property, value);},deleteProperty(target, property) {logCallback(`删除属性: ${property}`);return Reflect.deleteProperty(target, property);}});}
}// 使用示例
const user = LoggingProxy.createLogger({name: '张三',age: 25
});

3. 访问控制代理

class AccessControlProxy {static createPrivateProperties(target, privateProps = []) {return new Proxy(target, {get(target, property) {if (privateProps.includes(property)) {throw new Error(`无法访问私有属性: ${property}`);}return Reflect.get(target, property);},set(target, property, value) {if (privateProps.includes(property)) {throw new Error(`无法修改私有属性: ${property}`);}return Reflect.set(target, property, value);},deleteProperty(target, property) {if (privateProps.includes(property)) {throw new Error(`无法删除私有属性: ${property}`);}return Reflect.deleteProperty(target, property);}});}
}

4. 缓存代理

class CachingProxy {static createCached(target, ttl = 5000) {const cache = new Map();return new Proxy(target, {apply(target, thisArg, args) {const key = JSON.stringify(args);const now = Date.now();if (cache.has(key)) {const [result, timestamp] = cache.get(key);if (now - timestamp < ttl) {return result;}}const result = Reflect.apply(target, thisArg, args);cache.set(key, [result, now]);return result;}});}
}// 使用示例
const expensiveOperation = CachingProxy.createCached((x, y) => {console.log('执行计算...');return x + y;}
);

最佳实践 ⭐

  1. 结合Reflect API使用
// 推荐
const handler = {get(target, prop, receiver) {return Reflect.get(target, prop, receiver);}
};// 不推荐
const handler = {get(target, prop) {return target[prop];}
};
  1. 合理使用代理链
function createProxyChain(...handlers) {return (target) => {return handlers.reduce((proxy, handler) => {return new Proxy(proxy, handler);}, target);};
}
  1. 错误处理
const handler = {get(target, prop, receiver) {try {return Reflect.get(target, prop, receiver);} catch (error) {console.error(`获取属性 ${prop} 失败:`, error);return undefined;}}
};

性能考虑 ⚡

  1. 避免过度代理
// 不推荐
function createProxy(obj) {return new Proxy(obj, {get: (target, prop) => Reflect.get(target, prop)  // 无意义的代理});
}// 推荐
function createProxy(obj) {return obj;  // 如果不需要拦截,直接返回原对象
}
  1. 缓存代理结果
class ProxyCache {constructor() {this.cache = new WeakMap();}createProxy(target, handler) {if (this.cache.has(target)) {return this.cache.get(target);}const proxy = new Proxy(target, handler);this.cache.set(target, proxy);return proxy;}
}
  1. 合理使用可撤销代理
function createRevocableProxy(target, handler) {const { proxy, revoke } = Proxy.revocable(target, handler);// 在不需要时撤销代理setTimeout(() => {revoke();}, 5000);return proxy;
}

总结 📝

JavaScript的Proxy API提供了:

  1. 强大的对象操作拦截能力
  2. 灵活的代理模式实现方式
  3. 与Reflect API的完美配合
  4. 丰富的实际应用场景

💡 学习建议:

  • 深入理解各种代理拦截器
  • 掌握常用代理模式
  • 注意性能影响
  • 合理使用代理链
  • 始终做好错误处理

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

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

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

相关文章

如何优化Spark作业的性能

优化Spark作业的性能是一个综合性的任务&#xff0c;涉及多个方面的调整和优化。以下是一些关键的优化策略&#xff1a; 一、开发调优 避免创建重复的RDD&#xff1a; 对于同一份数据&#xff0c;只应该创建一个RDD&#xff0c;避免多次创建RDD来增加性能开销。在对不同的数据…

SOCKET建立简单的tcp服务端与客户端通信

socket是什么 socket可以使两台机子建立连接&#xff0c;就像连接风扇与电源的插座一样&#xff0c;socket可以使服务端与客户端建立连接&#xff0c;服务端就像供电厂&#xff0c;而客户端就像用电器&#xff0c;而socket就是连接二者的插座。 建立简单的连接 如果我们想在客…

blender笔记2

一、物体贴地 物体->变换->对齐物体 ->对齐弹窗(对齐模式&#xff1a;反方&#xff0c;相对于&#xff1a;场景原点&#xff0c;对齐&#xff1a;z)。 之后可以设置原点->原点--3d游标 二、面上有阴影 在编辑模式下操作过后&#xff0c;物体面有阴影。 数据-&g…

如何正确安装Stable Diffusion Web UI以及对应的xFormers

本文是我总结的步骤&#xff0c;验证了几次保证是对的。因为正确的安装 Stable Diffusion Web UI 以及对应的 xFormers 实在是太麻烦了&#xff0c;官方和网上的步骤都是残缺和分散的&#xff0c;加上国内网络速度不理想&#xff0c;所以需要一些额外步骤&#xff0c;之前研究出…

hive(hdfs)补数脚本

pb级别迁移通常要持续1个月以上。一般的过程是&#xff0c;全量迁移&#xff0c;追平数据&#xff0c;增量同步&#xff0c;校验&#xff0c;补数。 这里的指定补数脚本&#xff1a; 输入需要补数的表&#xff0c;如Input.txt&#xff0c;如果有分区则加补此分区&#xff0c;没…

Android JNI的理解与使用。

写在前面&#xff1a;Java相对于C/C来说是更高级的语言&#xff0c;隐藏了指针&#xff0c;可读性更高&#xff0c;更容易学习&#xff0c;但是无法直接操作硬件、运行速度较慢也是不可回避的硬伤。JNI就是Java官方定义的一套标准“接口”&#xff0c;用于Java和C/C之间互相调用…

如何在Odoo 18中创建记录规则Rule

如何在Odoo 18中创建记录规则Rule 记录规则是管理访问控制的关键&#xff0c;它能让你依据用户角色&#xff0c;定义谁可以在系统内查看、创建或修改特定记录。例如&#xff0c;公司中的普通员工只能查看或修改与与自己直接相关的数据&#xff0c;而经理则有权限访问和编辑所有…

idea 2019.3常用插件

idea 2019.3常用插件 文档 idea 2019.3常用插件idea 2023.3.7常用插件 idea 2019.3常用插件 插件名称插件版本说明1AceJump3.5.9AceJump允许您快速将插入符号导航到编辑器中可见的任何位置。只需按“ctrl&#xff1b;”&#xff0c;键入一个字符&#xff0c;然后在Ace Jump…

Windows网络安全基础

随着互联网的发展和普及&#xff0c;Windows网络安全问题愈发严重。在本文中&#xff0c;我们将会介绍Windows网络安全的基本概念&#xff0c;包括网络攻击类型、网络安全威胁、网络安全防御措施等等&#xff0c;帮助初学者更好地了解Windows网络安全。 一、网络攻击类型 网络…

大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(1)

大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(1) Apache Paimon 是一项流式数据湖存储技术&#xff0c;可以为用户提供高吞吐、低延迟的数据摄入、流式订阅以及实时查询能力。 读/写&#xff1a;Paimon 支持多种读/写数据和执行 OLAP 查询的方式。 对于读取&#x…

Node.js 中 cookie-parser 依赖详解

解析 HTTP 请求中的 Cookie 的 Node.js 中间件 一、安装 npm install cookie-parser 二、基本使用 const express require("express");const cookieParser require("cookie-parser");const app express();// 使用 cookie-parser 中间件app.use(cook…

Linux入侵检查流程

1. 初步信息收集 1.1 系统信息 • 目的&#xff1a;了解当前系统的基本情况&#xff0c;包括操作系统版本、内核版本等。 • 命令&#xff1a; cat /etc/redhat-release 1.2 网络信息 目的&#xff1a;查看网络连接状态、开放端口以及防火墙规则&#xff0c;排查异常网络活…

Elasticsearch 混合搜索 - Hybrid Search

作者&#xff1a;来自 Elastic Valentin Crettaz 了解混合搜索、Elasticsearch 支持的混合搜索查询类型以及如何制作它们。 本文是三篇系列文章中的最后一篇&#xff0c;深入探讨了向量搜索&#xff08;又称语义搜索&#xff09;的复杂性以及它在 Elasticsearch 中的实现方式。…

本地客户端调用火山方舟 DeepSeek R1API教程

本地第三方AI聊天机器人客户端调用 DeepSeek R1&#xff0c;目前火山云 DeepSeek R1 API 目前测试下高速推理速度&#xff0c;不卡顿&#xff0c;联网搜索能力&#xff0c;可以访问更多联网信息50万免费 tokens&#xff0c;超出后全网最低价。 目录 一、火山方舟 DeepSeek R1A…

华为最新OD机试真题-通过软盘拷贝文件-Python-OD统一考试(E卷)

最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 题目描述 有一名 科学家只 想要从一台古董电脑中拷贝文件到自己的电脑中加以研究。 但此电脑除了有一个3.5寸软盘驱动器以外,没有任何手段可以将文件持贝出来,而且只有一张软盘…

第四十三篇——零和博弈(鞍点理论):如何找到双方的平衡点?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 这篇文章再读依然茅塞顿开&#xff1b;有很多需要自己去吸收的东西&#…

ESP32 ESP-IDF TFT-LCD(ST7735 128x160)自定义组件驱动显示

ESP32 ESP-IDF TFT-LCD(ST7735 128x160)自定义组件驱动显示 &#x1f33f;驱动参考来源&#xff1a;https://blog.csdn.net/weixin_59250390/article/details/142691848&#x1f4cd;个人相关驱动内容文章&#xff1a;《ESP32 ESP-IDF TFT-LCD(ST7735 128x160) LVGL基本配置和使…

请解释一下Standford Alpaca格式、sharegpt数据格式-------deepseek问答记录

1 Standford Alpaca格式 json格式数据。Stanford Alpaca 格式是一种用于训练和评估自然语言处理&#xff08;NLP&#xff09;模型的数据格式&#xff0c;特别是在指令跟随任务中。它由斯坦福大学的研究团队开发&#xff0c;旨在帮助模型理解和执行自然语言指令。以下是该格式的…

数据治理中 大数据处理一般都遵循哪些原则

在数据治理中&#xff0c;大数据处理通常遵循以下原则&#xff1a; 最小化原则&#xff1a;企业应只收集实现特定目的所需的数据&#xff0c;避免数据冗余和安全风险。 合法性原则&#xff1a;企业必须遵守相关法律法规&#xff0c;确保数据处理符合法律要求&#xff0c;降低法…

Python 基础-使用dict和set

dict Python内置了字典&#xff1a;dict的支持&#xff0c;dict全称dictionary&#xff0c;在其他语言中也称为map&#xff0c;使用键-值&#xff08;key-value&#xff09;存储&#xff0c;具有极快的查找速度。 举个例子&#xff0c;假设要根据同学的名字查找对应的成绩&am…