reflect 提供统一、可预测的元编程方法,推荐用 reflect.ownkeys 替代 object.keys 获取含 symbol 的完整自有键,配合 reflect.getownpropertydescriptor 按需采集属性元信息,并与 proxy 组合实现健壮拦截,摒弃已废弃的 reflect.enumerate。

Reflect 是 JavaScript 中专为元编程设计的内置对象,它把原本分散在 Object、函数原型甚至操作符中的底层能力,集中封装成一套清晰、可预测的方法。用 Reflect 统一处理对象属性的枚举与元编程,核心在于:用 Reflect.enumerate(已废弃)、Reflect.ownKeys、Reflect.getOwnPropertyDescriptor 等方法替代 for...in、Object.keys()、Object.getOwnPropertyDescriptors() 等传统方式,从而获得更一致的行为、更好的错误处理和更明确的语义。
用 Reflect.ownKeys 替代 Object.keys / Object.getOwnPropertyNames
Reflect.ownKeys 返回对象自身所有属性键(包括字符串和 Symbol),顺序严格遵循规范定义(先整数索引,再字符串键,最后 Symbol 键),且不会被 Object.prototype 上的属性干扰。它比 Object.keys 更底层、更完整,也比 Object.getOwnPropertyNames 多包含 Symbol 属性。
- 它始终返回一个数组,出错时抛出异常(如传入 null/undefined),行为可预测;Object.keys 则会对非对象参数做强制转换,容易掩盖问题
- 适合需要完整枚举(含 Symbol)或依赖标准遍历顺序的场景,比如序列化、代理拦截、深克隆
- 示例:Reflect.ownKeys({ a: 1, [Symbol('b')]: 2, 0: 'zero' }) → ['0', 'a', Symbol(b)]
用 Reflect.getOwnPropertyDescriptor + Reflect.ownKeys 实现安全的属性元信息采集
单独调用 Reflect.getOwnPropertyDescriptor(obj, key) 可以获取指定键的属性描述符(value、writable、enumerable、configurable 等),配合 Reflect.ownKeys 就能完整、可控地遍历并检查每个自有属性的元数据,避免 for...in 的原型链污染或 Object.getOwnPropertyDescriptors 的“全量快照”开销。
- 对每个 key 调用 Reflect.getOwnPropertyDescriptor,能精确判断该属性是否可枚举、是否为访问器、是否可配置等
- 相比 Object.getOwnPropertyDescriptors(obj),它支持按需查询,适合只关心部分属性或动态键名的场景
- 注意:它只查自有属性,不查找原型链上的属性——这正是元编程中“显式控制”的关键
结合 Proxy 与 Reflect 实现可组合的属性枚举拦截
Proxy 的 handler 方法(如 ownKeys、getOwnPropertyDescriptor)常需返回符合规范的结果。此时直接委托给 Reflect 对应方法,是最安全、最规范的做法——Reflect 方法的设计初衷就是为 Proxy 提供默认行为。
- 例如在 ownKeys 拦截中:return Reflect.ownKeys(target),既保证返回值格式合法,又保留原始枚举逻辑
- 在 getOwnPropertyDescriptor 中调用 Reflect.getOwnPropertyDescriptor(target, key),可避免手动构造描述符时遗漏字段或违反 invariant
- 这种“Reflect + Proxy”组合,让自定义枚举逻辑(如过滤私有属性、注入虚拟键)既干净又健壮
避开已废弃的 Reflect.enumerate,拥抱现代枚举范式
Reflect.enumerate 曾用于获取可枚举属性(类似 for...in 的结果),但因语义模糊、与 for...in 行为不完全对齐,已在 ES2016 中被移除。现在统一推荐:
- 要获取所有自有键(含 Symbol)→ 用 Reflect.ownKeys
- 要获取可枚举的自有字符串键 → 先 Reflect.ownKeys,再对每个 key 调用 Reflect.getOwnPropertyDescriptor 并检查 enumerable: true
- 要模拟 for...in(含原型链上可枚举属性)→ 手动遍历原型链,对每层调用 Reflect.ownKeys + 描述符检查,而非依赖已不可靠的 legacy 方式










