news 2026/4/23 11:28:05

理解 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/19 0:27:51

【异常】豆包TTS语音合成常见报错及SSML代码实现解决方案

一、报错内容 在豆包TTS语音合成使用过程中,出现以下三类典型读音错误,影响语音输出准确性: 符号读音错误:输入文本“睡眠时间7-8小时”,预期输出“睡眠时间7至8小时”,实际输出“睡眠时间7减8小时”; 多音字发音错误:输入文本“偏好”(正确读音为piān hǎo,“好”…

作者头像 李华
网站建设 2026/4/20 7:42:24

基于数据挖掘的中风智能预测系统

温馨提示:文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 系统概述 随着医疗大数据的快速发展,利用机器学习技术辅助疾病诊断已成为智慧医疗的重要方向。本项目开发了一套基于数据挖掘的中风智能预测系统。该系统旨在通过分析患者的性别、年龄、生活习惯…

作者头像 李华
网站建设 2026/4/18 10:49:17

Windows右键菜单优化全攻略:告别卡顿的3大诊断与4步修复方案

Windows右键菜单优化全攻略:告别卡顿的3大诊断与4步修复方案 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 当点击文件后那个小圆圈不停旋转&#x…

作者头像 李华
网站建设 2026/4/20 18:24:49

终极英雄联盟智能助手:三步实现游戏自动化完全指南

终极英雄联盟智能助手:三步实现游戏自动化完全指南 【免费下载链接】LeagueAkari ✨兴趣使然的,功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari 还在为繁琐的…

作者头像 李华
网站建设 2026/4/21 0:39:07

NCM文件转换神器:NCMconverter完全使用指南

NCM文件转换神器:NCMconverter完全使用指南 【免费下载链接】NCMconverter NCMconverter将ncm文件转换为mp3或者flac文件 项目地址: https://gitcode.com/gh_mirrors/nc/NCMconverter 还在为网易云音乐下载的ncm格式文件无法播放而烦恼吗?NCMconv…

作者头像 李华
网站建设 2026/4/22 7:28:56

百度网盘极速下载终极指南:3步实现高速下载体验

百度网盘极速下载终极指南:3步实现高速下载体验 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 百度网盘作为国内广泛使用的云存储服务,其下载速度限制…

作者头像 李华