proxy可拦截get/set等操作实现无侵入日志与埋点:get中记录属性访问(过滤高频属性),set中统计关键字段变更(对比新旧值),支持组合拦截与分层策略,但需注意性能、递归代理及框架兼容性。

JavaScript 中 Proxy 可以通过拦截对象的 get、set 等操作,在不修改原对象逻辑的前提下,自动记录属性访问行为,实现轻量级日志与埋点统计。
用 Proxy 拦截属性读取(get)并记录访问日志
每次读取属性时触发 get 拦截器,可记录时间、属性名、调用栈等上下文信息:
- 使用
Reflect.get(target, prop, receiver)保证默认行为不被破坏 - 通过
console.trace()或new Error().stack获取简单调用位置(生产环境建议采样或禁用) - 避免高频属性(如
toString、valueOf)重复打点,可用白名单或正则过滤
示例:
const logAccess = (target, prefix = '') => new Proxy(target, {
get(obj, prop) {
if (typeof prop === 'string' && !/^__|constructor|toString|valueOf$/.test(prop)) {
console.log(`[ACCESS] ${prefix || 'obj'}[${prop}] at`, new Date().toISOString());
}
return Reflect.get(obj, prop);
}
});
拦截属性赋值(set)并统计变更行为
在 set 拦截中可判断是否为首次赋值、值是否变化、是否属于关键字段(如 userId、pageName),用于用户行为埋点:
- 对比旧值与新值(注意引用类型需深比较或仅比对基本类型)
- 结合业务标识(如页面模块名)统一打点,便于后续归因分析
- 异步上报时建议节流或批量合并,避免阻塞主线程
示例:
const trackChanges = (target, module = 'unknown') => new Proxy(target, {
set(obj, prop, value) {
const oldValue = obj[prop];
const changed = !Object.is(oldValue, value);
if (changed && ['userId', 'status', 'tab'].includes(prop)) {
console.log(`[CHANGE] ${module}.${prop}:`, oldValue, '→', value);
// sendToAnalytics({ event: 'field_update', module, prop, oldValue, newValue: value });
}
return Reflect.set(obj, prop, value);
}
});
组合多个拦截器实现分层埋点策略
单一 Proxy 可同时处理多种操作,也可用工厂函数封装不同埋点维度(如性能采集、错误捕获、用户路径):
- 用闭包维护独立状态(如访问计数、首次访问时间戳)
- 对嵌套对象递归代理需谨慎:避免无限代理,可用 WeakMap 缓存已代理对象
- 配合
has、ownKeys拦截可捕获in操作和Object.keys()调用,补全埋点覆盖场景
注意事项与性能提醒
Proxy 是透明代理,但不是零成本。实际使用中需规避常见陷阱:
- 避免在 Proxy 内部直接访问被代理对象的属性(会造成无限递归),一律走
Reflect - 不能代理非对象(null、原始值),需提前校验
- Vue 3 响应式底层即基于 Proxy,若与框架共用对象,注意拦截优先级与副作用冲突
- 生产环境建议关闭日志输出,只保留条件触发的轻量上报逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











