
core-js 中的 Array.isTemplateObject识别真正的模板字符串数组【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js导读Array.isTemplateObject(value)是 TC39 提案 Array.isTemplateObject为主体结合模块实现与单元测试讲解该提案的语义、core-js 的判定算法、引入方式与典型应用场景读完你可以直接在项目中使用core-js/proposals/array-is-template-object这一入口获得该能力。提案背景模板对象为什么值得被识别ES2015 引入的模板字符串除了求值之外还有一个容易被忽略的细节标签模板调用会把“模板字面量的原始内容”以冻结数组的形式传给标签函数。例如(it it)\qwe${ 123 }asd中标签函数收到的第一个参数是一个冻结数组[qwe, asd]并且它还带有一个同样被冻结的raw属性保存未经转义处理的原始片段[qwe, asd]。问题在于语言规范只定义了“模板调用产生冻结数组”这一行为却没有提供“检测一个值是不是这种模板数组”的内建 API。库作者往往只能通过判断Object.isFrozen(value) value.raw ! undefined之类的启发式手段猜测既不准确也不安全。Array.isTemplateObject提案正是要填补这个空缺它让开发者可以用一个标准、可靠的方法判断某个值是否真的是模板调用产物从而在编译期/运行时工具链例如安全地消费模板字符串、识别 CSS-in-JS 的模板调用、实现高性能模板缓存等场景中做出正确分支。core-js 中的模块与入口在 core-js 中该功能由 proposal 级模块承载源码位于 esnext.array.is-template-object.js。它被编入以下入口提案入口proposals/array-is-template-object.js对应core-js/proposals/array-is-template-objectfull 目录的单方法入口full/array/is-template-object.js对应core-js(-pure)/full/array/is-template-object聚合入口full/array/index.js 第 9 行也会引入该模块stage 入口作为 Stage 2 提案它被列入 stage/2.js 第 4 行因此引入core-js/stage/2或更早的 stage 包也会自动带上该能力。对应的 TypeScript 签名与原文档一致class Array { static isTemplateObject(value: any): boolean }推荐的最小化引入方式// 仅引入本提案 import core-js/proposals/array-is-template-object; // 或只引入单个方法core-js-pure 同样适用 import core-js-pure/full/array/is-template-object; Array.isTemplateObject((it it)qwe${ 123 }asd); // true判定算法源码级拆解原文档只给出了方法签名与一行示例真正的判定细节在模块实现中。它内部先定义了一个辅助函数isFrozenStringArray(array, allowUndefined)随后isTemplateObject由两次该检查组合而成var isFrozenStringArray function (array, allowUndefined) { if (!isFrozen || !isArray(array) || !isFrozen(array)) return false; var index 0; var length array.length; var element; while (index length) { element array[index]; if (!(typeof element string || (allowUndefined element undefined))) { return false; } } return length ! 0; }; $({ target: Array, stat: true, sham: true, forced: true }, { isTemplateObject: function isTemplateObject(value) { if (!isFrozenStringArray(value, true)) return false; var raw value.raw; return isFrozenStringArray(raw, false) raw.length value.length; } });判定条件可以逐条拆解为必须是数组且已冻结isFrozenStringArray内部先经isArray来自 internals/is-array.js按规范IsArray抽象操作实现确认是数组再要求Object.isFrozen为真。真正的模板数组在创建时就是冻结的这一条能直接排除绝大多数普通对象与可变数组。数组不能为空返回length ! 0说明空数组一律不算模板对象。元素必须全部是字符串逐个遍历元素非 string 类型直接返回false。注意第一次调用isFrozenStringArray(value, true)传入allowUndefined true——根据提案语义模板数组的插值槽位对应的元素可以是undefined对应undefined插值或尾随空槽场景因此此处允许undefined元素通过。raw属性必须是冻结字符串数组value.raw需再次通过isFrozenStringArray(raw, false)。这次allowUndefined false因为规范中raw数组的所有元素一定是字符串同时要求raw.length value.length确保主数组与原始片段数组一一对应。只有四条同时满足Array.isTemplateObject才返回true。一个没有raw属性的冻结字符串数组例如Object.freeze([hello])会在第 4 步被拒绝这正是它区别于“启发式猜测”的地方。从源码结构看$来自 internals/export.js它负责把方法挂到全局Array上。其中stat: true表示挂为静态方法forced: true表示即使宿主环境原生实现了同名方法也强制覆盖保证行为一致而sham: true会通过 export.js 给方法打上非标准的sham标记——因为 JavaScript 引擎目前无法真正“创建”一个模板对象该方法只能识别真模板数组、无法凭空构造因此它本质上是一个“sham”不完全的 polyfill而非完整 polyfill。测试验证行为边界一览单元测试 对判定边界做了完整的覆盖可以直接作为行为契约阅读assert.isFunction(isTemplateObject); assert.arity(isTemplateObject, 1); assert.name(isTemplateObject, isTemplateObject); assert.looksNative(isTemplateObject); assert.nonEnumerable(Array, isTemplateObject); assert.false(isTemplateObject(undefined)); assert.false(isTemplateObject(null)); assert.false(isTemplateObject({})); assert.false(isTemplateObject(function () { return arguments; }())); assert.false(isTemplateObject([])); assert.false(isTemplateObject(freeze([])), frozen string array without .raw should return false #1); assert.false(isTemplateObject(freeze([hello])), frozen string array without .raw should return false #2); const template Function(return (it it)qwe${ 123 }asd)(); if (template) assert.true(isTemplateObject(template));测试揭示的边界语义基础类型一律为falseundefined、null、普通对象、arguments对象都不满足“冻结数组”前提空数组即使冻结为falsefreeze([])返回false冻结字符串数组但缺少raw为falsefreeze([hello])会通过前三步检查却在raw检查处失败这验证了“光靠冻结字符串元素不足以冒充模板数组”的设计真模板调用返回true测试用Function(return (it it)\qwe${ 123 }asd)()动态构造一次真实标签模板调用外层用Function是为了在无法解析模板的环境下安全降级再断言isTemplateObject(template) true。使用注意事项只识别、不构造由于sham属性该方法无法与原生实现进行“能力对等”的替换——它只能判断某个值是不是语言层面真实产生的模板数组不能把任意冻结数组“升级”为模板数组。对插值槽位为undefined的情况宽容主数组允许undefined元素allowUndefined true而raw数组不允许二者判定策略不同阅读代码或撰写测试时需要注意这一不对称。引入时机该能力属于 proposal 级Stage 2API 与语义仍可能随 TC39 讨论演进在生产环境应通过core-js/proposals/array-is-template-object或core-js(-pure)/full/array/is-template-object显式引入避免整套 stage 包带来额外体积。环境兼容实现依赖Object.isFrozen与Array.isArray后者在 internals/is-array.js 中有classof兜底不支持这些能力的极老环境需要更早的 core-js 版本先行填充基础能力。小结Array.isTemplateObject把“模板字符串调用产物的识别”从启发式猜测提升为标准化 API。core-js 以 proposal 模块的形式提供了完整实现判定算法严格校验“冻结数组 全字符串元素 非空 冻结的raw 长度一致”并配以覆盖全部边界条件的单元测试。需要识别标签模板调用的库或工具可以直接通过core-js/proposals/array-is-template-object引入并在运行时安全地依赖这一判定结果。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考