core-js 中 ECMAScript Reflect 全面解析:模块清单、内置方法签名与多入口使用指南
core-js 中 ECMAScript Reflect 全面解析模块清单、内置方法签名与多入口使用指南【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js本篇指南以 docs/web/docs/features/ecmascript/reflect.md 为骨架系统梳理 core-js 对 ECMAScriptReflect内置对象的 polyfill 实现涵盖 14 个独立模块的完整清单、TypeScript 签名、es | stable | actual | full四套入口路径的用法并深入源码剖析每个方法的底层实现与引擎 bug 修复逻辑。读完本文你将能够按需精确引入任意Reflect方法理解 core-js 如何在不支持的运行环境中忠实还原Reflect语义并能用Reflect.ownKeys、Reflect.construct等写出可运行、可验证的实战代码。一、为什么 core-js 需要 polyfill ReflectReflect是 ES2015ES6引入的全局内置对象提供了与Object上对应静态方法一一映射的反射语义操作但它并非构造函数不能new。两者最直观的区别在于返回值约定Object.defineProperty失败时抛异常而Reflect.defineProperty返回falsedelete运算符在严格模式下对不可配置属性会抛错而Reflect.deleteProperty返回false。此外Reflect还提供Object没有的方法如Reflect.construct、Reflect.ownKeys、Reflect.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模拟实现标记——这一点在下面的源码剖析中会反复出现。二、Modules14 个 Reflect 模块完整清单原文档列出 core-js 为Reflect提供的全部模块每个模块独立成文件、可单独引入文件均位于 packages/core-js/modules/方法对应模块文件作用Reflect.applyes.reflect.apply.js以指定this与参数列表调用函数Reflect.constructes.reflect.construct.js以参数数组调用构造函数Reflect.definePropertyes.reflect.define-property.js定义属性失败返回falseReflect.deletePropertyes.reflect.delete-property.js删除属性不可配置返回falseReflect.getes.reflect.get.js读取属性值可走原型链与 getterReflect.getOwnPropertyDescriptores.reflect.get-own-property-descriptor.js获取自有属性描述符Reflect.getPrototypeOfes.reflect.get-prototype-of.js获取原型Reflect.hases.reflect.has.js等价于in运算符Reflect.isExtensiblees.reflect.is-extensible.js判断对象是否可扩展Reflect.ownKeyses.reflect.own-keys.js返回自有键含 SymbolReflect.preventExtensionses.reflect.prevent-extensions.js阻止扩展Reflect.setes.reflect.set.js设置属性值失败返回falseReflect.setPrototypeOfes.reflect.set-prototype-of.js设置原型失败返回false此外入口聚合文件 es/reflect/index.js 还会额外引入 es.reflect.to-string-tag.js 与es.object.to-string保证Reflect[Symbol.toStringTag] ReflectObject.prototype.toString.call(Reflect)输出[object Reflect]这是规范对Reflect对象的额外要求。三、Built-ins signatures完整方法签名与逐项说明原文档给出了Reflect命名空间的完整 TypeScript 签名逐方法继承如下namespace Reflect { apply(target: Function, thisArgument: any, argumentsList: Arraymixed): any; construct(target: Function, argumentsList: Arraymixed, 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): Arraystring | 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.get与Reflect.set的receiver参数可指定 getter/setter 执行时的this实现代理语义。Reflect.ownKeys返回的数组同时包含字符串键与 Symbol 键且返回类型为Arraystring | symbol。Reflect.setPrototypeOf的注释required __proto__ - IE11表明在 IE11 及更新版本中要求引擎支持__proto__才能正确 polyfill 该语义源码中该模块仅在objectSetPrototypeOf存在时才定义见 es.reflect.set-prototype-of.js。四、源码级剖析core-js 如何还原 Reflect 语义4.1Reflect.ownKeys一行委托 内置键收集es.reflect.own-keys.js 非常简洁直接委托给internals/own-keys工具它内部合并Object.getOwnPropertyNames与Object.getOwnPropertySymbols的结果从而同时覆盖字符串键与 Symbol 键这正是Reflect.ownKeys区别于Object.keys仅返回可枚举字符串键的核心。4.2Reflect.apply检测 MS Edge 的省略参数 buges.reflect.apply.js 用fails检测旧版 MS Edge 允许省略argumentsList参数的偏差行为OPTIONAL_ARGUMENTS_LIST一旦检测到就forced强制覆盖为规范实现先aCallable(target)校验可调用性再anObject(argumentsList)校验参数列表最终调用functionApply完成调用。4.3Reflect.construct两大引擎 bug 与零参数优化es.reflect.construct.js 是模块中最复杂的实现它检测并修复了两类已知问题NEW_TARGET_BUGFirefox Nightly原生实现接受第三个参数newTarget但不会依据它创建this导致nativeConstruct(fn, [], F) instanceof F为假。ARGS_BUG某些引擎调用Reflect.construct(fn)省略参数列表会失败。当存在上述任一 bug 时模块被标记为forced且sham使用自定义实现。在Target newTarget的常见路径下代码对 04 个参数做了new Target(...)的展开优化参数更多时则通过Function.prototype.bind拼接参数后new。当newTarget被改写时则从newTarget.prototype创建原型对象、以该对象为this调用Target并处理返回值是否为对象的两种情况。这解释了为什么Reflect.construct(C, [20, 22])可以构造出instance.c 42的实例见下文示例。4.4Reflect.get/Reflect.set原型链递归与 receiver 语义es.reflect.get.js 的内部函数$get是递归实现先查自有属性描述符数据描述符直接返回值访问器描述符则以receiver为this调用 getter若属性不存在则沿getPrototypeOf向上递归直到原型为null。当target receiver时走快速路径target[propertyKey]。es.reflect.set.js 的$set则完整实现了规范写入算法处理只读数据属性返回false、在receiver上执行defineProperty、调用原型链上的 setter并通过MS_EDGE_BUG检测修复了 MS Edge 17-18 中允许向原型只读属性所在对象写入的错误。4.5Reflect.defineProperty/Reflect.deleteProperty/Reflect.hases.reflect.define-property.js 用ERROR_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标记getOwnPropertyDescriptor、getPrototypeOf分别依赖internals/descriptors与internals/correct-prototype-getter的能力检测在不支持属性描述符或原生原型 getter 的环境下标记sham即该实现只是近似模拟。is-extensible、prevent-extensions、set-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.js、packages/core-js/stable/reflect/、packages/core-js/actual/reflect/、packages/core-js/full/reflect/目录。core-js与core-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.js、tests/unit-global/es.reflect.construct.js、tests/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 | full与core-js(-pure)的组合提供了从全局注入到无污染副本的灵活加载方式而fails检测驱动的forced/sham机制如Reflect.construct的NEW_TARGET_BUG、Reflect.apply的 MS Edge 省略参数问题确保了在旧引擎上也能获得与规范一致的行为。按需引入core-js/es/reflect/xxx单方法入口即可在保持体积可控的同时获得可靠的反射语义支持。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考