news 2026/4/15 17:06:03

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
理解 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 作为键,完全没问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/12 9:36:27

小学娃近视防控不费妈!这款眼调节训练灯,学习护眼一步到位

家有小学娃,近视防控堪称家长的“心头大事”。看着孩子每天趴在书桌前读书、写作业,长时间近距离用眼,不少家长既担心孩子视力下降,又苦于没有省心的解决方案——强迫孩子做眼保健操、定时远眺,往往要花费大量时间监督…

作者头像 李华
网站建设 2026/4/15 12:13:08

02、打不开某个网站

本质上是客户端到认证服务器的 TCP 三层/四层连不通,或 SSL/TLS 握手/证书校验失败。先按下面 3 步定位,再按对应方案处理即可。一、定位错误1.1、ping / curl 测试三层 ping 不通 网络 / DNS / 防火墙问题 curl 能通但 4**/5** 服务活…

作者头像 李华
网站建设 2026/4/3 6:28:53

Spring事务

学习资料:Spring 事务详解 | JavaGuide Spring支持的事务本质上是数据库支持的事务,所以前提也是数据库支持事务 Spring 不直接实现事务,而是通过 事务管理器(PlatformTransactionManager) 来对接不同底层技术&#…

作者头像 李华
网站建设 2026/4/15 5:29:17

1000人网络设计冗余型

只做到DHCP中继服务了&#xff0c;还有电信的pppoe拨号上网、telnet、策略路由等还没做&#xff0c;等下次更新&#xff0c;配置需要对照拓扑图来看<HX_SW1>dis cu # sysname HX_SW1 # undo info-center enable # vlan batch 2 to 5 200 800 999 # stp instance 1 root …

作者头像 李华
网站建设 2026/4/13 6:47:12

PyCausalSim:基于模拟的因果发现的Python框架

做 A/B 测试或者分析转化率的时候&#xff0c;经常会碰到那个老生常谈的问题&#xff1a; “这数据的波动到底是干预引起的&#xff0c;还是仅仅是相关性&#xff1f;” 传统的分析手段和机器学习擅长告诉你什么能预测结果&#xff0c;但预测不等于因果。而在做决策&#xff…

作者头像 李华
网站建设 2026/4/15 11:37:09

技术工具类文章仿写专家Prompt指南

技术工具类文章仿写专家Prompt指南 【免费下载链接】LeagueAkari ✨兴趣使然的&#xff0c;功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari 一、核心任务定义 你是一名专业的文章仿…

作者头像 李华