at() 方法不触发 Proxy 的 get 拦截,因其是原生方法,直接通过内部槽访问底层数组;方括号访问如 arr[-1] 才触发 get;需手动代理 at 属性才能拦截。

at() 方法在 Proxy 数组中不会自动触发索引解构逻辑,它直接调用目标数组的 at(),不经过 get 拦截。这是因为 at() 是数组原型上的原生方法,其内部访问机制绕过 Proxy 的属性读取拦截(即不触发 get),而是通过内部槽(internal slot)直接操作底层数组对象。
为什么 at(-1) 不走 Proxy 的 get 拦截
Proxy 的 get(target, prop, receiver) 拦截的是「属性访问」,例如 arr[-1]、arr.length 或 arr[0] 这类方括号语法。而 at() 是一个函数调用,其执行过程如下:
- 引擎识别
arr.at(-1)是对数组原型方法的调用 - 内部直接读取目标数组的 length 和元素存储结构(如 Array exotic object 的 [[ArrayLength]] 和元素索引槽)
- 不把
-1当作字符串属性名去调用get,因此你的get拦截器完全不会收到-1这个 key
对比:at() vs 方括号访问在 Proxy 中的行为差异
假设你用 Proxy 包装了一个数组,并在 get 中加了日志:
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
-
proxy[2]→ 触发get(target, "2", proxy),可自定义返回值或转换逻辑 -
proxy.at(2)→ 不触发get,直接返回目标数组第 2 个元素(正向) -
proxy.at(-1)→ 不触发get,直接计算target[target.length - 1]并返回 -
proxy[-1]→ 触发get(target, "-1", proxy),但原生数组没有 "-1" 属性,通常返回undefined
如何让 at() 行为受控(需手动代理方法)
若你确实需要拦截 at() 调用(比如做越界审计、日志、或重写负索引语义),不能依赖 get,而应:
- 在 Proxy 的
get拦截中,对prop === "at"返回一个包装后的函数 - 该函数接收参数后,先执行自定义逻辑,再调用原始
target.at(...) - 示例:const proxied = new Proxy(arr, { get(t, p) { return p === "at" ? (...args) => { console.log("at called with", args); return t.at(...args); } : t[p]; } });
实际影响与注意事项
这种行为差异意味着:
- 你不能靠
get拦截来统一处理所有“取元素”操作 ——at()是个例外 - 对 Proxy 数组做响应式封装(如 Vue 或 Solid 的响应式系统)时,
at()调用不会触发依赖追踪,除非手动包裹 - 若目标数组本身被冻结或不可扩展,
at()仍可安全调用;而proxy[-1]可能因get返回undefined导致误判

















