core-js 的 ECMAScript Object 补丁全景:模块清单、类型签名、入口点与实现原理
2026/9/23 18:24:41 网站建设 项目流程

core-js 的 ECMAScript Object 补丁全景:模块清单、类型签名、入口点与实现原理

【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js

本文基于 core-js 仓库的官方文档 docs/web/docs/features/ecmascript/object.md,系统梳理 ECMAScript 规范中Object内建对象在 core-js 中的全部补丁模块、TypeScript 类型签名、按需导入入口点,并结合 packages/core-js/modules 下的真实源码剖析assigngroupByhasOwnfromEntries__proto__等关键方法的底层实现与兼容性修复策略。读完本文,你将能够精准定位任意Object方法的补丁文件、正确选择最小化的导入路径,并理解 core-js 如何在老引擎上还原 ES2015+ 语义。

一、Object 相关补丁模块全景

core-js 将 ES 规范中的每一个Object方法拆分为独立的模块文件,统一放在 packages/core-js/modules 目录下,命名规则为es.object.<method>.jses.前缀表示该特性已进入正式 ECMAScript 规范)。原文档列出的完整模块清单如下:

  • es.object.assign
  • es.object.create
  • es.object.define-getter
  • es.object.define-property
  • es.object.define-properties
  • es.object.define-setter
  • es.object.entries
  • es.object.freeze
  • es.object.from-entries
  • es.object.get-own-property-descriptor
  • es.object.get-own-property-descriptors
  • es.object.get-own-property-names
  • es.object.get-prototype-of
  • es.object.group-by
  • es.object.has-own
  • es.object.is
  • es.object.is-extensible
  • es.object.is-frozen
  • es.object.is-sealed
  • es.object.keys
  • es.object.lookup-getter
  • es.object.lookup-setter
  • es.object.prevent-extensions
  • es.object.proto
  • es.object.to-string
  • es.object.seal
  • es.object.set-prototype-of
  • es.object.values

这些模块被聚合入口 packages/core-js/es/object/index.js 统一require,并最终导出path.Object(即全局Object本身)。注意该聚合入口还会一并加载es.symboles.json.to-string-tages.math.to-string-tages.reflect.to-string-tag等关联模块——这是因为Symbol.toStringTagObject.prototype.toString标签机制的基础。

二、Built-ins 类型签名:一份可校验的 API 契约

原文档给出了Object补丁后完整 API 的 TypeScript 签名,这是理解 core-js 覆盖范围最直接的参照:

class Object { toString(): string; // ES2015+ fix: @@toStringTag support __defineGetter__(property: PropertyKey, getter: Function): void; __defineSetter__(property: PropertyKey, setter: Function): void; __lookupGetter__(property: PropertyKey): Function | void; __lookupSetter__(property: PropertyKey): Function | void; __proto__: Object | null; // required a way setting of prototype - will not in IE10-, it's for modern engines like Deno static assign(target: Object, ...sources: Array<Object>): Object; static create(prototype: Object | null, properties?: { [property: PropertyKey]: PropertyDescriptor }): Object; static defineProperties(object: Object, properties: { [property: PropertyKey]: PropertyDescriptor })): Object; static defineProperty(object: Object, property: PropertyKey, attributes: PropertyDescriptor): Object; static entries(object: Object): Array<[string, mixed]>; static freeze(object: any): any; static fromEntries(iterable: Iterable<[key, value]>): Object; static getOwnPropertyDescriptor(object: any, property: PropertyKey): PropertyDescriptor | void; static getOwnPropertyDescriptors(object: any): { [property: PropertyKey]: PropertyDescriptor }; static getOwnPropertyNames(object: any): Array<string>; static getPrototypeOf(object: any): Object | null; static groupBy(items: Iterable, callbackfn: (value: any, index: number) => key): { [key]: Array<mixed> }; static hasOwn(object: object, key: PropertyKey): boolean; static is(value1: any, value2: any): boolean; static isExtensible(object: any): boolean; static isFrozen(object: any): boolean; static isSealed(object: any): boolean; static keys(object: any): Array<string>; static preventExtensions(object: any): any; static seal(object: any): any; static setPrototypeOf(target: any, prototype: Object | null): any; // required __proto__ - IE11+ static values(object: any): Array<mixed>; }

几个值得注意的语义细节:

  • toString()标注为 "ES2015+ fix: @@toStringTag support":旧引擎的原生toString不认识Symbol.toStringTag,core-js 通过 es.object.to-string 在检测到TO_STRING_TAG_SUPPORT不足时,用内部实现 internals/object-to-string 覆盖Object.prototype.toString,从而支持[object Foo]这类自定义标签输出。
  • __proto__访问器:注释明确指出在 IE10- 中不可用,它面向的是 Deno 这类现代引擎。从源码 es.object.proto 看,其修复条件是DESCRIPTORS && getPrototypeOf && setPrototypeOf && ({}[PROTO] !== ObjectPrototype),即仅在原生缺失__proto__访问器时才通过defineBuiltInAccessor补上,且 setter 内部会先用isPossiblePrototype校验新原型是否合法。
  • setPrototypeOf__proto__的依赖关系:注释 "required__proto__- IE11+" 说明在 IE11 上setPrototypeOf的可用性依赖__proto__访问器被正确安装。

三、Entry Points:按需加载的入口点清单

core-js 的核心理念是"只用多少,加载多少"。原文档给出了Object相关全部入口点,路径模板为core-js(-pure)/es|stable|actual|full/object[/<method>]

core-js(-pure)/es|stable|actual|full/object core-js(-pure)/es|stable|actual|full/object/assign core-js(-pure)/es|stable|actual|full/object/is core-js(-pure)/es|stable|actual|full/object/set-prototype-of core-js(-pure)/es|stable|actual|full/object/get-prototype-of core-js(-pure)/es|stable|actual|full/object/create core-js(-pure)/es|stable|actual|full/object/define-property core-js(-pure)/es|stable|actual|full/object/define-properties core-js(-pure)/es|stable|actual|full/object/get-own-property-descriptor core-js(-pure)/es|stable|actual|full/object/get-own-property-descriptors core-js(-pure)/es|stable|actual|full/object/group-by core-js(-pure)/es|stable|actual|full/object/has-own core-js(-pure)/es|stable|actual|full/object/keys core-js(-pure)/es|stable|actual|full/object/values core-js(-pure)/es|stable|actual|full/object/entries core-js(-pure)/es|stable|actual|full/object/get-own-property-names core-js(-pure)/es|stable|actual|full/object/freeze core-js(-pure)/es|stable|actual|full/object/from-entries core-js(-pure)/es|stable|actual|full/object/seal core-js(-pure)/es|stable|actual|full/object/prevent-extensions core-js/es|stable|actual|full/object/proto core-js(-pure)/es|stable|actual|full/object/is-frozen core-js(-pure)/es|stable|actual|full/object/is-sealed core-js(-pure)/es|stable|actual|full/object/is-extensible core-js/es|stable|actual|full/object/to-string core-js(-pure)/es|stable|actual|full/object/define-getter core-js(-pure)/es|stable|actual|full/object/define-setter core-js(-pure)/es|stable|actual|full/object/lookup-getter core-js(-pure)/es|stable|actual|full/object/lookup-setter

入口点语法详解(详见官方文档 docs/web/docs/usage.md):

  • 命名空间层级es(仅稳定 ES 特性)→stable(稳定 ES + Web 标准)→actual(稳定 + Web 标准 + stage 3 提案)→full(全部特性,含早期提案)。官方建议优先使用/actual/,因为它覆盖了所有实际可用的 JavaScript 特性,又不包含主要用于实验的不稳定早期提案。
  • pure 变体core-js-pure不污染全局命名空间,适合库作者在依赖中安全使用;core-js是全局版本。
  • prototo-string两个入口仅存在于core-js(无-pure变体):原因在于这两个模块直接修改Object.prototype,无法在不污染原型的前提下以 pure 方式提供,这与 pure 版本"原型方法转换为静态方法"的定位一致。
  • 实际使用示例:import "core-js/actual/object/group-by"只加载Object.groupBy一个补丁;import "core-js/full/object"则一次性加载上文聚合入口 packages/core-js/es/object/index.js 列出的全部es.object.*模块。仓库中已生成对应的具体入口文件,例如 packages/core-js/es/object/assign.js、packages/core-js/es/object/group-by.js、packages/core-js/es/object/has-own.js。

四、源码级原理:关键方法的兼容性实现

1.Object.assign:针对 Edge 与 V8 旧版 Bug 的修复

es.object.assign 本身只是一个薄壳,真正逻辑位于 internals/object-assign.js。该文件先执行两个原生实现的缺陷检测:

  • Edge 顺序 Bug:在属性 getter 动态新增不可枚举属性时,原生assign的结果顺序错误;
  • V8 符号与顺序 Bug:原生实现不复制Symbol键、或复制后属性顺序不稳定。

只有Object.assign !== assign(即检测失败)时才注入自实现。自实现的关键点:

  • toObject(target)保证目标必须是对象(否则抛TypeError);
  • 对每个 source 使用IndexedObject包装(兼容字符串等原始值);
  • 键列表由objectKeys(S)getOwnPropertySymbols(S)拼接而成,即同时复制字符串键与符号键
  • 在无DESCRIPTORS(不支持属性描述符的引擎)时直接赋值,否则仅复制可枚举属性(propertyIsEnumerable过滤),严格对齐规范的[[OwnPropertyKeys]]+EnumerableOwnProperties语义。

2.Object.groupBy:处理原始值输入与 WebKit Bug

Object.groupBy是较新的 ES 特性,实现见 es.object.group-by。源码先做特性检测:

var DOES_NOT_WORK_WITH_PRIMITIVES = !nativeGroupBy || fails(function () { return nativeGroupBy('ab', function (it) { return it; }).a.length !== 1; });

该检测针对 WebKit bug #271524——某些 WebKit 版本无法正确处理字符串等原始值输入。若检测失败则注入 polyfill,其算法要点:

  • requireObjectCoercible(items)+aCallable(callbackfn)做入参校验;
  • 结果对象用create(null)创建(无原型对象),因此内部可安全使用key in obj判断键是否存在,规避了部分 IE 版本在整数键上hasOwnProperty行为异常的问题;
  • iterate遍历可迭代对象,toPropertyKey将回调返回值规范化为属性键,doesNotExceedSafeInteger防止索引溢出;
  • 新键用createProperty(obj, key, [value])创建数组,已有键则push追加。

3.Object.hasOwnObject.fromEntries等薄封装

  • es.object.has-own 直接复用内部工具 internals/has-own-property,本质是规范化的Object.prototype.hasOwnProperty调用,避免对象自带hasOwnProperty被覆盖导致的误判。
  • es.object.from-entries 内部通过iterate(iterable, fn, { AS_ENTRIES: true })[key, value]二元组迭代任意可迭代对象(Map、数组、生成器等),再用createProperty写入,保证键始终被正确处理(含符号键、数字键的字符串化)。

4.Object.prototype.__proto__:面向 Deno 的访问器补丁

es.object.proto 的源码注释特别提到:"Deno 2.9+ patch this accessor, so we can't useinfor feature detection"——即 Deno 较新版本会自行修补该访问器,因此不能用'__proto__' in {}这类方式做特性探测,必须用({})[PROTO] !== ObjectPrototype判断实际值。补丁本身通过defineBuiltInAccessorObject.prototype上安装configurable: true的 getter/setter,getter 返回getPrototypeOf(toObject(this)),setter 在原型合法(isPossiblePrototype)且目标为对象时才执行setPrototypeOf

5.Object.prototype.toString@@toStringTag修复

es.object.to-string 在TO_STRING_TAG_SUPPORT为 false 时,用 internals/object-to-string 覆盖原型上的toString。该实现会检查对象的Symbol.toStringTag,输出[object <Tag>]格式,同时保持对内置类型(ArrayFunctionRegExp等)标签的兼容。

五、完整示例:验证补丁后的行为

以下是原文档给出的全部运行示例,可直接在加载core-js后于任意支持环境执行验证:

let foo = { q: 1, w: 2 }; let bar = { e: 3, r: 4 }; let baz = { t: 5, y: 6 }; Object.assign(foo, bar, baz); // => foo = { q: 1, w: 2, e: 3, r: 4, t: 5, y: 6 } Object.is(NaN, NaN); // => true Object.is(0, -0); // => false Object.is(42, 42); // => true Object.is(42, '42'); // => false function Parent() { /* empty */ } function Child() { /* empty */ } Object.setPrototypeOf(Child.prototype, Parent.prototype); new Child() instanceof Child; // => true new Child() instanceof Parent; // => true ({ [Symbol.toStringTag]: 'Foo', }).toString(); // => '[object Foo]' Object.keys('qwe'); // => ['0', '1', '2'] Object.getPrototypeOf('qwe') === String.prototype; // => true Object.values({ a: 1, b: 2, c: 3 }); // => [1, 2, 3] Object.entries({ a: 1, b: 2, c: 3 }); // => [['a', 1], ['b', 2], ['c', 3]] for (let [key, value] of Object.entries({ a: 1, b: 2, c: 3 })) { console.log(key); // => 'a', 'b', 'c' console.log(value); // => 1, 2, 3 } const object = { a: "1" }; Object.defineProperty(object, 'notWritable', { value: true, writable: false }); // Shallow object cloning with prototype and descriptors: Object.create(Object.getPrototypeOf(object), Object.getOwnPropertyDescriptors(object)); // => {"a": "1", "notWritable": true} const target = { a: "9" }; const source = { b: "8" }; Object.defineProperty(source, 'notWritable', { value: true, writable: false }); // Mixin: Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); // => {"a": "9", "b": "8", "notWritable": true} const map = new Map([['a', 1], ['b', 2]]); Object.fromEntries(map); // => { a: 1, b: 2 } class Unit { constructor(id) { this.id = id; } toString() { return `unit${ this.id }`; } } const units = new Set([new Unit(101), new Unit(102)]); Object.fromEntries(units.entries()); // => { unit101: Unit { id: 101 }, unit102: Unit { id: 102 } } Object.hasOwn({ foo: 42 }, 'foo'); // => true Object.hasOwn({ foo: 42 }, 'bar'); // => false Object.hasOwn({}, 'toString'); // => false Object.groupBy([1, 2, 3, 4, 5], it => it % 2); // => { 1: [1, 3, 5], 0: [2, 4] }

几个示例背后的实现佐证:

  • Object.keys('qwe')返回['0', '1', '2']Object.getPrototypeOf('qwe')返回String.prototype,说明 core-js 的补丁遵循规范对原始值(primitive)的ToObject装箱处理;
  • Object.create(Object.getPrototypeOf(object), Object.getOwnPropertyDescriptors(object))Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))两个组合分别演示了"带原型与描述符的浅克隆"和"保留writable: false的 mixin",它们的正确性依赖于getOwnPropertyDescriptors补丁如实返回描述符对象;
  • Object.groupBy的返回对象没有原型(内部create(null)),因此示例中得到的{ 1: [...], 0: [...] }是一个普通对象但不会携带Object.prototype上的键,这在处理用户数据时更安全。

六、与 Babel 生态的配合

Object补丁同样深度集成于 Babel 工具链(详见 docs/web/docs/usage.md):

  • @babel/polyfill本质上就是core-js/stableregenerator-runtime的组合,现已废弃;
  • 使用@babel/preset-env时设置useBuiltIns: 'entry'corejs: '3.50'(建议精确到次版本号),Babel 会按目标环境自动把import 'core-js/es'拆解为仅必要的模块。例如针对chrome 71目标,import 'core-js/stable'可能被替换为import 'core-js/modules/es.object.from-entries'等少量模块,这正是"入口点 + 模块拆分"设计价值的体现。

七、小结

core-js 对 ECMAScriptObject的覆盖遵循一套高度模块化的工程模式:每个方法一个es.object.*.js模块(源码见 packages/core-js/modules),通过特性检测决定是否注入 polyfill;对外提供es/stable/actual/full四级命名空间与按方法细分的入口点;对内依赖 packages/core-js/internals 中的原子工具函数保证语义严格对齐规范。无论是处理assign的 Edge/V8 顺序缺陷、groupBy的 WebKit 原始值缺陷,还是__proto__在 Deno 等现代引擎上的访问器修补,其核心思路都是"优先使用原生实现、仅在检测到缺陷时注入等价实现",这也是 core-js 能长期保持可靠性的根本原因。

【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询