Reflect API 不执行参数校验,错误由底层操作在运行时抛出;其方法如 Reflect.get()、set() 等直接封装内部抽象操作,报错时机和类型取决于目标语义;与 Object 方法相比,Reflect 更适合代理且返回更一致,但不可替代前置参数校验。

Reflect API 本身不执行参数类型或合法性检查,它把参数原样转发给底层操作,错误由目标操作(如对象属性访问、代理 trap 等)在运行时抛出。
Reflect 方法不校验参数
与传统 Object 方法不同,Reflect 的所有方法(如 Reflect.get()、Reflect.set()、Reflect.defineProperty())不会提前验证参数是否合法。例如:
-
Reflect.get(null, 'prop')不会立刻报错,而是等到实际尝试从null读取属性时才抛出TypeError; -
Reflect.set({}, 'key', value, undefined)中第四个参数(receiver)为undefined是允许的,仅在需要时参与原型链查找; -
Reflect.defineProperty({}, 'x', null)会直接失败,因为defineProperty内部要求第三个参数是对象,但这个检查发生在引擎层面,不是 Reflect 主动做的。
错误时机取决于目标操作语义
Reflect 只是封装了 JS 内部的抽象操作(如 [[Get]]、[[Set]]、[[DefineOwnProperty]]),因此报错位置和类型完全由这些底层操作决定:
- 对非对象调用
Reflect.get(target, key)→ 抛出TypeError: Cannot convert undefined or null to object; - 向不可写属性赋值(且严格模式下)→
Reflect.set()返回false,不抛错;非严格模式下静默失败; -
Reflect.construct()要求第一个参数是构造函数,否则立即抛TypeError—— 这是因为 [[Construct]] 规范明确要求 callable,引擎前置校验。
与 Object 方法的关键区别
Reflect 设计初衷是让操作更可预测、更易代理,因此它统一返回布尔值或结果值,而非抛异常(部分方法如 Reflect.defineProperty 仍可能抛错,因底层操作本身就会):
-
Object.defineProperty(obj, key, desc)失败时直接 throw; -
Reflect.defineProperty(obj, key, desc)失败时也 throw,但它的返回值语义更一致(成功返回true,失败抛错),便于在 Proxy handler 中使用; -
Reflect.has(obj, key)总是返回布尔值,而key in obj行为相同,但 Reflect 版本可被 Proxy 拦截,且不触发 getter。
实际开发中的建议
不要依赖 Reflect 做参数防护,应在调用前自行校验:
- 确保
target是对象(可用obj != null && typeof obj === 'object'); - 对关键操作(如 defineProperty、set)加 try/catch,尤其在 Proxy 或动态场景中;
- 用
Reflect.getPrototypeOf()替代Object.getPrototypeOf()更安全——前者对非对象返回null,后者会强制转对象并可能引发意外行为。

















