当前位置: 首页 > news >正文

理解 Proxy 原理及如何拦截 Map、Set 等集合方法调用实现自定义拦截和日志——含示例代码解析

先理解 Proxy 的核心思想

Proxy 就像一个“拦截器”,它可以“监听”一个对象的操作,比如:

  • 访问对象的属性(读取) → 触发get拦截器
  • 给对象的属性赋值(写入) → 触发set拦截器
  • 调用对象的方法 → 其实是先访问方法(触发get),再执行它

但集合类型(Map、Set 等)不直接用属性赋值来写入数据

  • Map 写入数据是调用它的set(key, value)方法
  • Set 写入数据是调用它的add(value)方法
  • 读取数据是调用 Map 的get(key)或 Set 的has(value)方法

所以,我们想拦截“写入”操作,就要拦截这些方法的调用。


Proxy 怎么拦截方法调用?

  • 当你访问proxyMap.set,会触发 Proxy 的get拦截器,告诉你访问了set方法。
  • 这时我们返回一个“包装函数”,这个函数内部可以插入自定义逻辑(比如打印日志),然后再调用原始的set方法。
  • 这样就实现了“拦截写入操作”。

具体示例:拦截 Map 的读取和写入

constmap=newMap();consthandler={get(target,prop,receiver){// 访问属性或方法时触发constorigMethod=target[prop];if(typeoforigMethod==='function'){// 如果访问的是方法,返回一个包装函数returnfunction(...args){if(prop==='set'){console.log(`写入操作:set(${args[0]},${args[1]})`);}elseif(prop==='get'){console.log(`读取操作:get(${args[0]})`);}// 调用原始方法returnorigMethod.apply(target,args);};}// 访问普通属性,直接返回returnReflect.get(target,prop,receiver);}};constproxyMap=newProxy(map,handler);proxyMap.set('name','CodeMoss');// 控制台输出:写入操作:set(name, CodeMoss)console.log(proxyMap.get('name'));// 控制台输出:读取操作:get(name)// 输出:CodeMoss

可以把它理解成:

  • 访问proxyMap.set→ Proxy 拦截,返回一个“带日志”的函数
  • 调用这个函数时,先打印日志,再调用真正的map.set

Set 也是类似的,只是写入方法叫add,读取方法叫has

constset=newSet();consthandler={get(target,prop,receiver){constorigMethod=target[prop];if(typeoforigMethod==='function'){returnfunction(...args){if(prop==='add'){console.log(`写入操作:add(${args[0]})`);}elseif(prop==='has'){console.log(`读取操作:has(${args[0]})`);}returnorigMethod.apply(target,args);};}returnReflect.get(target,prop,receiver);}};constproxySet=newProxy(set,handler);proxySet.add(123);// 控制台输出:写入操作:add(123)console.log(proxySet.has(123));// 控制台输出:读取操作:has(123)// 输出:true

WeakMap 和 WeakSet 也一样,只是它们的键或值必须是对象,且不能遍历

constweakMap=newWeakMap();consthandler={get(target,prop,receiver){constorigMethod=target[prop];if(typeoforigMethod==='function'){returnfunction(...args){if(prop==='set'){console.log('WeakMap 写入操作,键:',args[0],'值:',args[1]);}elseif(prop==='get'){console.log('WeakMap 读取操作,键:',args[0]);}returnorigMethod.apply(target,args);};}returnReflect.get(target,prop,receiver);}};constproxyWeakMap=newProxy(weakMap,handler);constobjKey={};proxyWeakMap.set(objKey,'secret');// 控制台输出:WeakMap 写入操作,键: {} 值: secretconsole.log(proxyWeakMap.get(objKey));// 控制台输出:WeakMap 读取操作,键: {}// 输出:secret

总结

  • Proxy 的get拦截器拦截的是“属性访问”,方法调用是先访问方法再执行。
  • 集合的写入和读取都是通过调用方法实现的,所以我们拦截方法访问,返回包装函数。
  • 包装函数里可以插入自定义逻辑(日志、权限等),然后调用原始方法完成操作。

把 const objKey = {}; 换成 map”,把 WeakMap 的键从一个普通对象{}换成一个 Map 对象。


先说明一点:

WeakMap 的键必须是对象,而 Map 本身是一个对象(它是一个构造函数实例),所以理论上是可以作为 WeakMap 的键的。


可以这样写:

constweakMap=newWeakMap();consthandler={get(target,prop,receiver){constorigMethod=target[prop];if(typeoforigMethod==='function'){returnfunction(...args){if(prop==='set'){console.log('WeakMap 写入操作,键:',args[0],'值:',args[1]);}elseif(prop==='get'){console.log('WeakMap 读取操作,键:',args[0]);}returnorigMethod.apply(target,args);};}returnReflect.get(target,prop,receiver);}};constproxyWeakMap=newProxy(weakMap,handler);// 这里用 Map 作为键constmapKey=newMap();proxyWeakMap.set(mapKey,'secret');// 控制台输出:WeakMap 写入操作,键: Map {} 值: secretconsole.log(proxyWeakMap.get(mapKey));// 控制台输出:WeakMap 读取操作,键: Map {}// 输出:secret

解释:

  • mapKey是一个 Map 实例,属于对象类型,可以作为 WeakMap 的键。
  • WeakMap 允许任何对象作为键,包括普通对象、数组、函数、甚至 Map、Set 等实例。
  • 用 Map 作为键,完全没问题。

http://www.cnnetsun.cn/news/27980.html

相关文章:

  • 【项目实战】Vercel 是一个让你的网站“瞬间上线”的云平台。Vercel 现在确实是技术圈的“当红炸子鸡”,尤其是在个人博客和前端开发领域。
  • Day28~实现strlen、strcpy、strncpy、strcat、strncat
  • 空洞骑士模组管理大师课:5个关键技巧让Scarab成为你的游戏管家
  • 实用方法:轻松实现NCM文件格式转换的完整解析
  • C++课后习题训练记录Day49
  • LeetCode 189. 旋转数组 | 三步反转最优解全拆解
  • downkyi视频下载:告别卡顿与画质损失的终极解决方案
  • 教你如何玩转DPDK开发中的KNI与内核交互,让网络速度翻倍!
  • Openresty驱动下的高性能Web网关实战
  • 百度网盘下载工具终极指南:快速突破限速的完整教程
  • C语言实现hashmap(附带源码)
  • jsonnet介绍和使用
  • 喜马拉雅音频数据采集:API接口分析与加密音频链接解密实战
  • 角色影像生成新纪元:Pony V7-Base引领AI创作革命
  • 论文格式修改排名:9大平台+在线一键优化
  • 论文写作效率低?十大AI生成平台,AIGC降重+赶due不熬夜
  • 文献引用规范考核要点解析与实践指南
  • 文献综述写作期末指南:方法、结构与常见问题解析
  • 期末文献研究论文的撰写方法与实践路径探讨
  • 基于 HID 协议的扩展功能指令定义方案
  • 模拟IC设计:集成电路与运算放大器大观
  • 6、Oracle数据库管理:文件与目录操作全解析
  • 12、Oracle数据库Linux服务器软件管理全攻略
  • 某聘新版AST解混淆(青春版)
  • 基于Spring Boot框架和vue的的诗词鉴赏与交流网站的设计与实现_96fdvu1s
  • 基于模型预测算法的混合储能微电网双层能量管理系统研究(Matlab代码实现)
  • 三极管:电子信息时代的核心“控制单元”,藏于设备中的关键器件
  • 1小时打造专属右键菜单工具:快马平台实战
  • 零基础用AI制作第一个Macyy风格网页
  • GG3M业务核心:需求满足与问题解决 | GG3M Business Core: Demand Satisfaction and Problem Solving