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

news/2025/2/21 8:38:37/

JavaScript代理模式专题 🎭

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

代理基础 🌟

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

javascript">// 基础代理操作
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. 基本拦截器

javascript">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. 高级拦截器

javascript">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. 函数和构造器拦截

javascript">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. 验证代理

javascript">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. 日志代理

javascript">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. 访问控制代理

javascript">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. 缓存代理

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

性能考虑 ⚡

  1. 避免过度代理
javascript">// 不推荐
function createProxy(obj) {return new Proxy(obj, {get: (target, prop) => Reflect.get(target, prop)  // 无意义的代理});
}// 推荐
function createProxy(obj) {return obj;  // 如果不需要拦截,直接返回原对象
}
  1. 缓存代理结果
javascript">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. 合理使用可撤销代理
javascript">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.ppmy.cn/news/1573839.html

相关文章

kube-proxy有什么作用?

kube-proxy 是 Kubernetes 中的一个重要组件&#xff0c;负责在每个节点上实现网络代理功能。它的主要作用是确保服务&#xff08;Service&#xff09;的网络流量能够正确地路由到集群中的后端 Pod&#xff0c;并支持多种服务类型&#xff08;如 ClusterIP、NodePort 和 LoadBa…

25届国网计算机考试知识难点及习题整理(持续更新)

25届国网计算机考试知识难点及习题整理&#xff08;持续更新&#xff09; 国网报名链接https://zhaopin.sgcc.com.cn/sgcchr/static/home.html 恭祝报名的同学全部上岸&#xff01;&#xff01;&#xff01; 同时需要原文件的在评论区私信我哦&#xff0c;我无偿发个每一个小…

测试使用Cursor中的deepseek-V3大模型辅助开发一个小程序

准备工作 下载工具 参考如下链接&#xff1a; https://mp.weixin.qq.com/s/TN10iS9VCkMkChmyxEplVw 创建项目 参考下图创建一个小程序项目&#xff0c;推荐使用智能创建&#xff0c;可以使用自然语言描述一下这个小程序的页面具体布局&#xff0c;实现的功能等&#xff0c;…

深入解析:短轮询、长轮询、长连接与WebSocket(原理到实现)

从原理到实战&#xff1a;深度剖析短轮询、长轮询、长连接及 WebSocket 的实现与差异 在日常开发中&#xff0c;短轮询、长轮询、长连接和WebSocket是常见的几种通信技术&#xff0c;各自适用于不同的场景。本文将深入分析这四种技术&#xff0c;从原理到实现&#xff0c;并探讨…

【DevOps构筑篇】用SELinux强化Docker的安全性

【DevOps构筑篇】用SELinux强化Docker的安全性 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战这篇文章中,我们将通过实际操作命令,练习在Rocky Linux上构建启用了SELinux的Docker。 按…

【蓝桥】二分法

1、简介 1.1 定义&#xff1a; 通过将问题的搜索范围一分为二&#xff0c;迭代地缩小搜索范围&#xff0c;直到找到目标或确定目标不存在 1.2 适用&#xff1a; 有序数据集合&#xff0c;且每次迭代可以将搜索范围缩小一半 1.3 本质&#xff1a; 枚举&#xff1a;利用数据结构…

【GESP】C++二级真题 luogu-b3865, [GESP202309 二级] 小杨的 X 字矩阵

GESP二级真题&#xff0c;多层循环、分支语句练习&#xff0c;难度★✮☆☆☆。 题目题解详见&#xff1a;https://www.coderli.com/gesp-2-luogu-b3865/ 【GESP】C二级真题 luogu-b3865, [GESP202309 二级] 小杨的 X 字矩阵 | OneCoderGESP二级真题&#xff0c;多层循环、分…

【pytest】编写自动化测试用例命名规范README

API_autoTest 项目介绍 1. pytest命名规范 测试文件&#xff1a; 文件名需要以 test_ 开头或者以 _test.py 结尾。例如&#xff0c;test_login.py、user_management_test.py 这样的命名方式&#xff0c;pytest 能够自动识别并将其作为测试文件来执行其中的测试用例。 测试类…