Proxy无法直接监控数组原生方法调用,但可通过代理数组实例的get拦截器重写filter/reduce等方法,或封装dedupeBySet等带埋点的去重函数实现可控监控。

Proxy 本身不能直接监控数组的原生方法(如 filter、Set 构造、reduce 等)是否被用于去重,因为这些是普通函数调用,不是对象自身的属性访问或赋值操作。但你可以通过拦截数组实例的**方法调用行为**(比如重写/代理其原型方法),或**包装常用去重逻辑**来实现监控目的。
监控数组原型上的方法调用(如 filter、flatMap 等)
数组去重常依赖 filter + indexOf、reduce、forEach 等。虽然 Proxy 无法自动捕获对 arr.filter(...) 的调用(因为 filter 是从原型链上获取的函数),但你可以:
- 用 Proxy 包裹数组,同时替换其
__proto__或使用setPrototypeOf指向自定义原型 - 在自定义原型中重写关键方法(如
filter、reduce),内部先记录日志再调用原生逻辑
示例:监控 filter 是否被用于去重(常见于 arr.filter((x, i) => arr.indexOf(x) === i))
// 注意:此方式会修改原型,仅适合调试或开发环境
const originalFilter = Array.prototype.filter;
<p>// 自定义监控版 filter
Array.prototype.filter = function (...args) {
console.log('[Proxy-like] Array.filter 被调用,可能用于去重');
// 简单启发式判断:回调中是否含 indexOf / lastIndexOf / includes 且参数为 this
const callback = args[0];
if (callback && typeof callback === 'function') {
const str = callback.toString();
if (/this.indexOf\s<em>(|this.includes\s</em>(|this.lastIndexOf\s*(/.test(str)) {
console.log('⚠️ 检测到疑似去重逻辑(基于 indexOf/includes)');
}
}
return originalFilter.apply(this, args);
};
用 Proxy 包裹数组并劫持读取/调用行为(更可控)
真正推荐的方式:不改原型,而是创建一个「可监控的数组壳」,把原生数组藏在 Proxy 内部,对关键方法做显式拦截。
注意:Proxy 对数组方法(如 push、filter)的拦截需通过 get 拦截器返回包装后的函数。
function createTrackedArray(arr) {
return new Proxy(arr, {
get(target, prop, receiver) {
const value = Reflect.get(target, prop, receiver);
<pre class="brush:php;toolbar:false;"> // 拦截 filter、reduce、flatMap 等可能用于去重的方法
if (typeof value === 'function' && ['filter', 'reduce', 'flatMap', 'map'].includes(prop)) {
return function (...args) {
console.log(`? 调用 ${prop}() —— 可能参与去重操作`);
// 可加额外判断:例如 filter 回调里是否有去重特征
if (prop === 'filter' && args[0]) {
const cbStr = args[0].toString();
if (/indexOf\(.*\)\s*===\s*i|includes\(.*\)/.test(cbStr)) {
console.log('? 高概率是去重调用');
}
}
return value.apply(target, args);
};
}
return value;
}}); }
// 使用 const arr = createTrackedArray([1, 2, 2, 3]); arr.filter((x, i) => arr.indexOf(x) === i); // 控制台输出监控信息
更实用:封装「带监控的去重函数」而非监控任意调用
与其费力拦截不可控的原生方法调用,不如主动封装常用去重逻辑,并统一埋点:
- 导出
dedupeByFilter、dedupeBySet、dedupeByReduce等函数 - 每个函数内部执行真实逻辑前打日志、计时、上报上下文
- 业务代码显式调用它们,形成可追踪、可维护的去重入口
示例:
export function dedupeBySet(arr) {
console.log('[DEDUPE] 使用 Set 去重,输入长度:', arr.length);
const start = performance.now();
const result = [...new Set(arr)];
console.log('[DEDUPE] 完成,耗时:', (performance.now() - start).toFixed(2), 'ms');
return result;
}
<p>// 在业务中
const unique = dedupeBySet([1,1,2,3]); // ✅ 明确、可监控、易测试
补充说明:为什么不能直接 Proxy 数组方法本身?
Array.prototype.filter 是函数对象,你可以 Proxy 它,但该 Proxy 只会在 全局 filter 被调用时 生效,无法区分是哪个数组调用的;而且现代 JS 引擎可能内联优化,导致代理失效。所以更可靠的是:
- 代理具体数组实例(用
get劫持方法访问) - 或封装明确语义的函数(推荐)
- 避免依赖字符串正则分析回调(有误报风险),必要时可约定回调加标记(如
cb.__isDedupeLogic = true)


















