proxy可拦截数组索引的get/set操作,但push等内置方法需手动包装才能触发拦截;length变化会触发set,而稀疏索引赋值仅触发对应索引的set,不触发中间空位。

Proxy 可以拦截对数组索引的读取(get)和写入(set),但要注意:**直接通过数字索引(如 arr[0] = x)触发的是 set 拦截,而数组长度变化、内置方法(如 push、pop、splice)默认不会触发 set 或 get,除非你显式重写这些方法**。
1. 基础索引赋值拦截(set)
当使用 arr[i] = value 修改某个索引时,set trap 会被触发。你可以检查 prop 是否为有效数组索引(即非负整数字符串),并做自定义逻辑:
示例:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
const arr = [1, 2, 3];
const proxy = new Proxy(arr, {
set(target, prop, value) {
if (/^\d+$/.test(prop) && Number(prop) >= 0) {
console.log(`设置索引 ${prop} 为 ${value}`);
// 可加校验、日志、通知等
}
target[prop] = value; // 必须赋值,否则不生效
return true;
}
});
proxy[0] = 99; // ✅ 触发 set,输出:设置索引 0 为 99
proxy.length = 2; // ✅ 也触发 set(length 是普通属性)
2. 拦截索引读取(get)
访问 proxy[i] 会触发 get。可用于响应式取值、懒计算、越界返回默认值等:
const proxy = new Proxy([10, 20], {
get(target, prop) {
if (/^\d+$/.test(prop)) {
const idx = Number(prop);
if (idx >= target.length) {
return undefined; // 或 throw, 或返回默认值
}
}
return target[prop]; // 兜底:方法、length、Symbol 等
}
});
console.log(proxy[5]); // undefined(不报错)
3. 拦截数组方法调用(需手动包装)
像 push、unshift、splice 这些方法内部修改索引,但不会逐个触发 set。要监控它们,必须在 get 中对方法名做特殊处理,返回包装后的新函数:
- 检测访问的属性是否为数组变异方法(如
'push') - 返回一个代理函数,在执行原方法后,手动触发自定义逻辑(如通知变更、校验新元素)
- 注意:要保留
this指向和参数透传
示例(拦截 push):
const proxy = new Proxy([1, 2], {
get(target, prop) {
if (prop === 'push') {
return function(...items) {
console.log('push 被调用,新增项:', items);
const result = target.push(...items);
// ✅ 此处可触发更新、校验、日志等
return result;
};
}
return target[prop];
}
});
proxy.push(3, 4); // 输出:push 被调用,新增项:[3, 4]
4. 注意事项与常见陷阱
-
数组长度自动更新不触发
set索引:例如arr[10] = 5会让length变成 11,但只触发一次set(prop='10'),不会触发对中间空位(如 '3'~'9')的set -
稀疏数组行为保持一致:Proxy 不改变 JS 数组语义,
arr[10] = x后arr[5]仍是undefined -
避免无限递归:在
set或get中操作target时,不要用proxy,否则会再次触发 trap - 性能敏感场景慎用:每个索引访问都经过函数调用,高频操作(如循环遍历)会有开销
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










