core-js 中 Symbol.metadata 与装饰器元数据提案(Decorator Metadata)的实现与使用指南
core-js 中 Symbol.metadata 与装饰器元数据提案Decorator Metadata的实现与使用指南【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-jsSymbol.metadata是 TC39 Decorator Metadata 提案的核心基础设施它为装饰器decorator机制提供标准化的元数据承载符号。本文基于 core-js 仓库中 docs/web/docs/features/proposals/symbol-metadata.md 文档结合 packages/core-js/modules/esnext.symbol.metadata.js 与 packages/core-js/modules/esnext.function.metadata.js 两个模块的源码深入讲解该提案在 core-js 中的内置签名、可用入口点entry points以及底层实现原理。读完本文你将清楚知道如何在自己的项目里按需引入Symbol.metadata与Function.prototype[metadata]并理解这两个 API 在 core-js 中的版本演进与测试验证方式。提案背景装饰器元数据需要什么基础Decorator Metadata 提案对应 stage 3 的decorator-metadata-v2版本的目标是让装饰器能够向被装饰的类、方法等目标对象附加结构化的元数据。该机制需要一个标准的键key来存放这些元数据而这个键就是Symbol.metadata这个 well-known symbol。在 core-js 中该提案由两个模块提供支撑esnext.symbol.metadata定义Symbol.metadata这个 well-known symbolesnext.function.metadata为所有函数继承自Function.prototype初始化默认的metadata值为null。两者协同工作symbol 提供全局唯一的键Function.prototype[metadata]提供每个函数默认的元数据槽位。这与Symbol.iterator、Symbol.asyncIterator等既有 well-known symbol 在 core-js 中的处理方式一脉相承。内置签名Built-ins signatures原文档给出了该提案在标准库中的类型签名class Symbol { static metadata: metadata; } class Function { metadata: null; }含义如下Symbol.metadata是Symbol构造器上的一个静态属性其值是一个 well-known symbol可用作装饰器写入元数据的唯一键Function.prototype[metadata]即所有函数实例共享的属性默认值为null表示尚未附加任何元数据。装饰器运行后可以将该值替换为存放元数据的具体对象。从源码验证签名实现在 core-js 中esnext.function.metadata模块完整实现了Function.prototype[metadata] null的语义见 packages/core-js/modules/esnext.function.metadata.jsuse strict; var wellKnownSymbol require(../internals/well-known-symbol); var defineProperty require(../internals/object-define-property).f; var METADATA wellKnownSymbol(metadata); var FunctionPrototype Function.prototype; // Function.prototype[metadata] // https://github.com/tc39/proposal-decorator-metadata if (FunctionPrototype[METADATA] undefined) { defineProperty(FunctionPrototype, METADATA, { value: null }); }关键细节通过wellKnownSymbol(metadata)获取与Symbol.metadata完全相同的 symbol 值保证两个模块使用的是同一个键仅在Function.prototype[METADATA] undefined时才注入即尊重宿主环境的原生实现不覆盖已有的非 undefined 值使用defineProperty定义属性符合符号属性默认不可枚举、不可写、不可配置的语义。而esnext.symbol.metadata模块则负责 symbol 本身的定义见 packages/core-js/modules/esnext.symbol.metadata.jsuse strict; var defineWellKnownSymbol require(../internals/well-known-symbol-define); // Symbol.metadata well-known symbol // https://github.com/tc39/proposal-decorators defineWellKnownSymbol(metadata);这里的defineWellKnownSymbol实现见 packages/core-js/internals/well-known-symbol-define.js会在全局Symbol上注册该键若Symbol尚未拥有该名称则将其值设为经过包装的 well-known symbol 模块生成的 symbol 值若宿主已原生提供则保持不动。这与 core-js 处理其他 well-known symbol 的策略完全一致。Entry points按需引入的入口点原文档列出了三个层次的入口点分别适用于不同的使用场景。1. 提案级入口一次引入完整提案core-js/proposals/decorator-metadata-v2该入口对应 packages/core-js/proposals/decorator-metadata-v2.js内容为同时引入上述两个模块use strict; // https://github.com/tc39/proposal-decorator-metadata require(../modules/esnext.function.metadata); require(../modules/esnext.symbol.metadata);在代码中使用方式为import core-js/proposals/decorator-metadata-v2;引入后全局环境中Symbol.metadata与Function.prototype[metadata]即全部就绪适合想完整体验该提案语义的场景。2. 细粒度入口按需引入单个能力core-js(-pure)/actual|full/symbol/metadata core-js(-pure)/actual|full/function/metadata其中core-js为污染全局的版本core-js-pure为不污染全局的纯版本actual命名空间对应当前已实装的实际特性不含早期不稳定提案full命名空间则包含全部特性。两个命名空间在 metadata 上目前指向同一实现。实际入口文件内容印证了这一点。以 packages/core-js/actual/symbol/metadata.js 为例use strict; require(../../modules/esnext.function.metadata); require(../../modules/esnext.symbol.metadata); var WrappedWellKnownSymbolModule require(../../internals/well-known-symbol-wrapped); module.exports WrappedWellKnownSymbolModule.f(metadata);该入口在加载时同时注入两个模块因为Function.prototype[metadata]依赖Symbol.metadata存在作为模块导出它通过well-known-symbol-wrapped返回Symbol.metadata的值便于在 CommonJS / 纯版本场景中以const metadata require(core-js-pure/actual/symbol/metadata)方式直接取用。而 packages/core-js/actual/function/metadata.js 则只注入esnext.function.metadata模块并导出nulluse strict; require(../../modules/esnext.function.metadata); module.exports null;这与Function.prototype[metadata]的默认值null保持一致说明该入口主要用于产生副作用注入原型属性其导出值对应默认元数据。full命名空间下的两个入口packages/core-js/full/symbol/metadata.js、packages/core-js/full/function/metadata.js均为对actual版本的简单转发module.exports parent。通过命名空间入口批量引入除了上述细粒度入口Symbol.metadata与Function.prototype[metadata]也会随对应的命名空间聚合入口被一起引入。例如 packages/core-js/actual/symbol/index.js 中同时require了esnext.function.metadata与esnext.symbol.metadata因此使用import core-js/actual或import core-js/full时metadata 相关能力也会被一并 polyfill具体聚合关系可查看 packages/core-js/actual/symbol/index.js 与 packages/core-js/actual/function/index.js。此外decorator-metadata-v2已被纳入 stage 3 集合见 packages/core-js/stage/3.js 中的require(../proposals/decorator-metadata-v2)因此使用import core-js/stage/3或import core-js/actual即可覆盖本提案。关于actual、full、stable、es等命名空间的差异与更多入口用法可参考仓库的 docs/web/docs/usage.md原文档中的{docs-version}/docs/usage#h-entry-points即对应此文件的 Entry points 小节。版本演进从 metadataKey 到 metadata值得注意的历史细节是core-js 中还保留着早期版本的入口 packages/core-js/proposals/decorator-metadata.jsuse strict; // TODO: Remove from core-js4 // https://github.com/tc39/proposal-decorator-metadata require(../modules/esnext.symbol.metadata-key);它引入的是Symbol.metadataKey见 packages/core-js/modules/esnext.symbol.metadata-key.js这是旧版提案使用的键名。源码中的TODO: Remove from core-js4注释明确标示该旧入口属于兼容性保留新项目应使用decorator-metadata-v2即Symbol.metadata入口。从源码结构可以推断Symbol.metadataKey是提案演进前的遗留 APIcore-js 为保证既有用户不破窗而暂时保留未来版本将移除。兼容性检测与测试验证core-js 的兼容性数据与测试用例均覆盖了这两个模块tests/compat/tests.js 中定义了特性检测esnext.function.metadata的检测逻辑为Function.prototype[Symbol.metadata] nullesnext.symbol.metadata的检测逻辑为直接取Symbol.metadata是否存在见 tests/compat/tests.js 与 tests/compat/tests.jstests/entries/unit.mjs 的入口单元测试验证了function/metadata加载后导出值为null、symbol/metadata加载后导出存在并校验了proposals/decorator-metadata与proposals/decorator-metadata-v2两个提案入口均可正常加载见 tests/entries/unit.mjs 与 tests/entries/unit.mjs。如果你需要自行检测运行环境是否原生支持该特性可直接复用上述检测逻辑// Symbol.metadata 是否存在 typeof Symbol.metadata ! undefined; // Function.prototype[metadata] 默认值是否为 null Function.prototype[Symbol.metadata] null;使用建议与注意事项优先使用actual命名空间按官方建议见 docs/web/docs/usage.md 中的 TIP 提示actual只包含已实装的实际特性适合生产环境full会额外带入早期不稳定提案主要用于实验。按需引入而非全量引入如果只用装饰器元数据推荐import core-js/actual或直接import core-js/actual/symbol/metadata避免引入无关 polyfill。不要直接使用modules内部路径packages/core-js/modules/下的文件是内部 API不会自动注入全部依赖且可能在 minor/patch 版本中变化应通过上述公开入口使用。警惕与原生实现的冲突core-js 在宿主已提供Symbol.metadata或非 undefined 的Function.prototype[metadata]时会跳过注入因此与浏览器、Node.js 等原生实现并存时是安全的但若项目同时混用多个 polyfill 方案仍建议将 core-js 入口放在应用入口文件顶部加载。综上Symbol.metadata与Function.prototype[metadata]虽只是两个极小的模块却是 Decorator Metadata 提案在 core-js 中的完整落地符号注册、原型默认值、多级入口、stage 演进与兼容性检测一应俱全。理解它们也就理解了 well-known symbol 类特性在 core-js 中的通用实现范式。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考