首页
/ core-js 中 ECMAScript Reflect 全面解析:模块清单、内置方法签名与多入口使用指南

core-js 中 ECMAScript Reflect 全面解析:模块清单、内置方法签名与多入口使用指南

2026-09-12 00:00:18作者:傅爽业Veleda

本篇指南以 docs/web/docs/features/ecmascript/reflect.md 为骨架,系统梳理 core-js 对 ECMAScript Reflect 内置对象的 polyfill 实现:涵盖 14 个独立模块的完整清单、TypeScript 签名、es | stable | actual | full 四套入口路径的用法,并深入源码剖析每个方法的底层实现与引擎 bug 修复逻辑。读完本文,你将能够按需精确引入任意 Reflect 方法,理解 core-js 如何在不支持的运行环境中忠实还原 Reflect 语义,并能用 Reflect.ownKeysReflect.construct 等写出可运行、可验证的实战代码。

一、为什么 core-js 需要 polyfill Reflect

Reflect 是 ES2015(ES6)引入的全局内置对象,提供了与 Object 上对应静态方法一一映射的反射语义操作,但它并非构造函数,不能 new。两者最直观的区别在于返回值约定Object.defineProperty 失败时抛异常,而 Reflect.defineProperty 返回 falsedelete 运算符在严格模式下对不可配置属性会抛错,而 Reflect.deleteProperty 返回 false。此外 Reflect 还提供 Object 没有的方法(如 Reflect.constructReflect.ownKeysReflect.apply)。

core-js 的定位是"标准库 polyfill",它通过 packages/core-js/modules/ 目录下一系列 es.reflect.*.js 模块,在旧引擎(尤其是 MS Edge 旧版本、旧版 Firefox 等)缺失或不完整实现 Reflect 时逐方法补齐。每个模块都通过 internals/export{ target: 'Reflect', stat: true } 的方式把方法挂到 Reflect 上,并针对已知引擎 bug 做 forced(强制覆盖)与 sham(模拟实现)标记——这一点在下面的源码剖析中会反复出现。

二、Modules:14 个 Reflect 模块完整清单

原文档列出 core-js 为 Reflect 提供的全部模块,每个模块独立成文件、可单独引入,文件均位于 packages/core-js/modules/

方法 对应模块文件 作用
Reflect.apply es.reflect.apply.js 以指定 this 与参数列表调用函数
Reflect.construct es.reflect.construct.js 以参数数组调用构造函数
Reflect.defineProperty es.reflect.define-property.js 定义属性,失败返回 false
Reflect.deleteProperty es.reflect.delete-property.js 删除属性,不可配置返回 false
Reflect.get es.reflect.get.js 读取属性值(可走原型链与 getter)
Reflect.getOwnPropertyDescriptor es.reflect.get-own-property-descriptor.js 获取自有属性描述符
Reflect.getPrototypeOf es.reflect.get-prototype-of.js 获取原型
Reflect.has es.reflect.has.js 等价于 in 运算符
Reflect.isExtensible es.reflect.is-extensible.js 判断对象是否可扩展
Reflect.ownKeys es.reflect.own-keys.js 返回自有键(含 Symbol)
Reflect.preventExtensions es.reflect.prevent-extensions.js 阻止扩展
Reflect.set es.reflect.set.js 设置属性值,失败返回 false
Reflect.setPrototypeOf es.reflect.set-prototype-of.js 设置原型,失败返回 false

此外,入口聚合文件 es/reflect/index.js 还会额外引入 es.reflect.to-string-tag.jses.object.to-string,保证 Reflect[Symbol.toStringTag] === 'Reflect'Object.prototype.toString.call(Reflect) 输出 [object Reflect]),这是规范对 Reflect 对象的额外要求。

三、Built-ins signatures:完整方法签名与逐项说明

原文档给出了 Reflect 命名空间的完整 TypeScript 签名,逐方法继承如下:

namespace Reflect {
  apply(target: Function, thisArgument: any, argumentsList: Array<mixed>): any;
  construct(target: Function, argumentsList: Array<mixed>, newTarget?: Function): Object;
  defineProperty(target: Object, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
  deleteProperty(target: Object, propertyKey: PropertyKey): boolean;
  get(target: Object, propertyKey: PropertyKey, receiver?: any): any;
  getOwnPropertyDescriptor(target: Object, propertyKey: PropertyKey): PropertyDescriptor | void;
  getPrototypeOf(target: Object): Object | null;
  has(target: Object, propertyKey: PropertyKey): boolean;
  isExtensible(target: Object): boolean;
  ownKeys(target: Object): Array<string | symbol>;
  preventExtensions(target: Object): boolean;
  set(target: Object, propertyKey: PropertyKey, V: any, receiver?: any): boolean;
  setPrototypeOf(target: Object, proto: Object | null): boolean; // required __proto__ - IE11+
}

逐项说明参数与返回值约定:

  • Reflect.apply(target, thisArgument, argumentsList):等价于 Function.prototype.apply,但 argumentsList 必须为类数组对象(源码中用 anObject 强制校验,见 es.reflect.apply.js)。
  • Reflect.construct(target, argumentsList, newTarget?):等价于 new target(...argumentsList);第三参数可改变 new.target,返回新实例对象。
  • Reflect.defineProperty / Reflect.deleteProperty / Reflect.set / Reflect.setPrototypeOf / Reflect.preventExtensions:失败不抛异常,返回 false
  • Reflect.getReflect.setreceiver 参数:可指定 getter/setter 执行时的 this,实现代理语义。
  • Reflect.ownKeys:返回的数组同时包含字符串键与 Symbol 键,且返回类型为 Array<string | symbol>
  • Reflect.setPrototypeOf 的注释 required __proto__ - IE11+:表明在 IE11 及更新版本中要求引擎支持 __proto__ 才能正确 polyfill 该语义(源码中该模块仅在 objectSetPrototypeOf 存在时才定义,见 es.reflect.set-prototype-of.js)。

四、源码级剖析:core-js 如何还原 Reflect 语义

4.1 Reflect.ownKeys:一行委托 + 内置键收集

es.reflect.own-keys.js 非常简洁,直接委托给 internals/own-keys 工具:它内部合并 Object.getOwnPropertyNamesObject.getOwnPropertySymbols 的结果,从而同时覆盖字符串键与 Symbol 键,这正是 Reflect.ownKeys 区别于 Object.keys(仅返回可枚举字符串键)的核心。

4.2 Reflect.apply:检测 MS Edge 的省略参数 bug

es.reflect.apply.jsfails 检测旧版 MS Edge 允许省略 argumentsList 参数的偏差行为(OPTIONAL_ARGUMENTS_LIST),一旦检测到就 forced 强制覆盖为规范实现:先 aCallable(target) 校验可调用性,再 anObject(argumentsList) 校验参数列表,最终调用 functionApply 完成调用。

4.3 Reflect.construct:两大引擎 bug 与零参数优化

es.reflect.construct.js 是模块中最复杂的实现,它检测并修复了两类已知问题:

  • NEW_TARGET_BUG(Firefox Nightly):原生实现接受第三个参数 newTarget,但不会依据它创建 this,导致 nativeConstruct(fn, [], F) instanceof F 为假。
  • ARGS_BUG:某些引擎调用 Reflect.construct(fn)(省略参数列表)会失败。

当存在上述任一 bug 时,模块被标记为 forcedsham,使用自定义实现。在 Target === newTarget 的常见路径下,代码对 0~4 个参数做了 new Target(...) 的展开优化;参数更多时则通过 Function.prototype.bind 拼接参数后 new。当 newTarget 被改写时,则从 newTarget.prototype 创建原型对象、以该对象为 this 调用 Target,并处理返回值是否为对象的两种情况。这解释了为什么 Reflect.construct(C, [20, 22]) 可以构造出 instance.c === 42 的实例(见下文示例)。

4.4 Reflect.get / Reflect.set:原型链递归与 receiver 语义

es.reflect.get.js 的内部函数 $get 是递归实现:先查自有属性描述符,数据描述符直接返回值,访问器描述符则以 receiverthis 调用 getter;若属性不存在则沿 getPrototypeOf 向上递归,直到原型为 null。当 target === receiver 时走快速路径 target[propertyKey]

es.reflect.set.js$set 则完整实现了规范写入算法:处理只读数据属性返回 false、在 receiver 上执行 defineProperty、调用原型链上的 setter,并通过 MS_EDGE_BUG 检测修复了 MS Edge 17-18 中"允许向原型只读属性所在对象写入"的错误。

4.5 Reflect.defineProperty / Reflect.deleteProperty / Reflect.has

  • es.reflect.define-property.jsERROR_INSTEAD_OF_FALSE 检测 MS Edge 抛异常而非返回 false 的偏差,且会先做 ToPropertyDescriptor 校验(getter/setter 必须是可调用或 undefined),非法描述符直接抛 TypeError——这与规范"属性描述符错误应抛异常、定义失败才返回 false"的边界一致。
  • es.reflect.delete-property.js 先取属性描述符,若 configurable === false 返回 false,否则执行 delete target[key]——这正是"严格模式下 delete 抛错、Reflect.deleteProperty 返回 false"的实现来源。
  • es.reflect.has.js 整个实现就是 propertyKey in target,与 in 运算符等价。

4.6 其余模块与 sham 标记

getOwnPropertyDescriptorgetPrototypeOf 分别依赖 internals/descriptorsinternals/correct-prototype-getter 的能力检测,在不支持属性描述符或原生原型 getter 的环境下标记 sham(即该实现只是近似模拟)。is-extensibleprevent-extensionsset-prototype-of 均以各自 internals 工具为基底,setPrototypeOf 在引擎不支持时直接不定义该属性。这些 forced/sham 标记正是 core-js 在 packages/core-js/modules/ 中统一采用的"先能力检测、后决定是否覆盖"的 polyfill 策略。

五、Entry points:四套入口与单方法精确引入

原文档给出了 Reflect 的完整入口路径模板(详见文档的 Entry points 章节):

core-js(-pure)/es|stable|actual|full/reflect
core-js(-pure)/es|stable|actual|full/reflect/apply
core-js(-pure)/es|stable|actual|full/reflect/construct
core-js(-pure)/es|stable|actual|full/reflect/define-property
core-js(-pure)/es|stable|actual|full/reflect/delete-property
core-js(-pure)/es|stable|actual|full/reflect/get
core-js(-pure)/es|stable|actual|full/reflect/get-own-property-descriptor
core-js(-pure)/es|stable|actual|full/reflect/get-prototype-of
core-js(-pure)/es|stable|actual|full/reflect/has
core-js(-pure)/es|stable|actual|full/reflect/is-extensible
core-js(-pure)/es|stable|actual|full/reflect/own-keys
core-js(-pure)/es|stable|actual|full/reflect/prevent-extensions
core-js(-pure)/es|stable|actual|full/reflect/set
core-js(-pure)/es|stable|actual|full/reflect/set-prototype-of

使用要点:

  • es / stable / actual / full 四个层级分别对应"仅标准 ES 特性""稳定特性(不含提案)""已按最新语义更新的当前版本""完整(含提案特性)"。Reflect 属于已定稿的 ES2015 特性,四套入口均可用,按项目对提案特性的开放程度选择即可。仓库中对应的聚合入口文件见 packages/core-js/es/reflect/index.jspackages/core-js/stable/reflect/packages/core-js/actual/reflect/packages/core-js/full/reflect/ 目录。
  • core-jscore-js-pure:前者直接修改全局 Reflect,后者通过 core-js-pure 包返回独立副本,不污染全局(packages/core-js-pure/override/ 存放对应的覆写模块)。
  • 单方法入口:如 core-js/es/reflect/own-keys 只引入 ownKeys 一个方法,避免全量引入带来的体积开销,适合按需加载。

典型用法:

// 引入全部 Reflect 方法(写入全局)
import 'core-js/es/reflect';

// 或只引入需要的单方法
import 'core-js/es/reflect/own-keys';
import 'core-js/es/reflect/construct';

// 使用 core-js-pure,不污染全局
const { Reflect: PureReflect } = require('core-js-pure/es/reflect');

六、Examples:可运行的实战示例

原文档给出了两个核心示例,这里完整继承并补充验证:

let object = { a: 1 };
Object.defineProperty(object, 'b', { value: 2 });
object[Symbol('c')] = 3;
Reflect.ownKeys(object); // => ['a', 'b', Symbol(c)]

function C(a, b) {
  this.c = a + b;
}

let instance = Reflect.construct(C, [20, 22]);
instance.c; // => 42

补充的实战场景:

// 1) Reflect.apply:以指定 this 调用,参数列表必须是类数组
Reflect.apply(String.prototype.replace, 'abc', ['b', 'x']); // => 'axc'

// 2) Reflect.set 失败时返回 false(严格模式 delete 会抛错,这里不会)
const frozen = Object.freeze({ a: 1 });
Reflect.set(frozen, 'a', 2);            // => false
Reflect.deleteProperty(frozen, 'a');    // => false

// 3) 带 receiver 的 getter 调用
const target = { get x() { return this.y; } };
Reflect.get(target, 'x', { y: 42 });    // => 42

// 4) has 等价于 in
Reflect.has({ a: 1 }, 'a');             // => true

// 5) construct 的 newTarget 参数
function Parent() { this.type = 'parent'; }
function Child() {}
const obj = Reflect.construct(Parent, [], Child);
obj instanceof Parent;                  // => false
obj instanceof Child;                   // => true

这些语义在仓库的单元测试中均有覆盖,例如 tests/unit-global/es.reflect.own-keys.jstests/unit-global/es.reflect.construct.jstests/unit-global/es.reflect.set.js 等,读者可在 tests/unit-global/ 目录下找到全部 14 个对应测试文件,作为行为验证与回归依据。

七、小结

core-js 对 Reflect 的 polyfill 是"逐方法模块化 + 引擎 bug 检测 + 规范语义还原"三者的结合:14 个 es.reflect.*.js 模块(另加 to-string-tag 补齐标签)均可独立引入;es | stable | actual | fullcore-js(-pure) 的组合提供了从全局注入到无污染副本的灵活加载方式;而 fails 检测驱动的 forced/sham 机制(如 Reflect.constructNEW_TARGET_BUGReflect.apply 的 MS Edge 省略参数问题)确保了在旧引擎上也能获得与规范一致的行为。按需引入 core-js/es/reflect/xxx 单方法入口,即可在保持体积可控的同时获得可靠的反射语义支持。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.16 K
2.78 K
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
904
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
934
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.96 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
606
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
398
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Markdown
77
23