Reflect.apply 是 Function.prototype.apply 的规范封装,语义更清晰且不依赖目标函数的 apply 方法,调用形式为 Reflect.apply(target, thisArgument, argumentsList),三个参数缺一不可。

Reflect.apply 本质是 Function.prototype.apply 的规范封装
它不是新功能,而是 ES6 把原本挂载在函数原型上的 apply 方法,抽出来作为 Reflect 的静态方法统一管理。好处是:语义更清晰(“反射式调用”),且不依赖目标函数是否具有 apply 方法(比如 Proxy 对象可能拦截掉原型方法,但 Reflect.apply 仍可工作)。
调用形式固定为:Reflect.apply(target, thisArgument, argumentsList),三个参数缺一不可,且顺序不能颠倒。
常见错误是把 thisArgument 写成 null 或 undefined 后没意识到非严格模式下会被自动转成全局对象——这在模块化环境里极易引发意外行为。
为什么不用 call/apply 而选 Reflect.apply
核心在于可靠性与可预测性。当 target 是 Proxy、稀疏数组方法、或被重写了 apply 的函数时,直接调用 fn.apply(thisArg, args) 可能被拦截、报错或返回非预期值;而 Reflect.apply 是底层反射操作,绕过用户层的代理逻辑,直抵原始调用语义。
使用场景包括:
- 安全地调用用户传入的任意函数(尤其在高阶函数或装饰器中)
- 在 Proxy 的
applytrap 中做兜底调用:return Reflect.apply(target, thisArg, args) - 需要和
Reflect.construct等保持 API 风格一致的元编程场景
参数细节与典型陷阱
argumentsList 必须是类数组或真数组;传 arguments 对象没问题,但传字符串、数字或 null 会直接抛 TypeError: CreateListFromArrayLike called on non-object。
thisArgument 不会自动绑定默认值——哪怕 target 是箭头函数,也照传不误(只是箭头函数忽略它)。这点和 Function.prototype.call 行为一致,但容易误以为 Reflect 会“智能处理”。
示例对比:
const obj = { x: 42 };
const fn = function() { return this.x; };
// ✅ 正确:显式传入 this 和参数数组
Reflect.apply(fn, obj, []);
// ❌ 报错:第三个参数不是可遍历对象
Reflect.apply(fn, obj, "hello");
// ❌ 无效:箭头函数无视 thisArgument,但 Reflect.apply 仍要求你传
const arrow = () => this.x;
Reflect.apply(arrow, { x: 99 }, []); // 返回 undefined,不是 99
性能与兼容性现实考量
现代引擎对 Reflect.apply 和 func.apply 的优化程度基本一致,性能差异可忽略。但要注意:IE 完全不支持 Reflect,Node.js 0.12–4.x 也不支持;若需兼容,得加 polyfill 或降级到 Function.prototype.apply.call(不推荐,可读性差)。
真正容易被忽略的是:Reflect.apply 不会触发 Proxy 的 get 或 has 拦截,但它本身可以被 Proxy 包裹——也就是说,如果你对 Reflect.apply 做了代理,那它就不再是“底层反射”了。

















