For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-string-cooked.md.
  • 简体中文
  • String.cooked S1

    提案概览
    提案速览

    该提案引入了一个静态的 String.cooked 方法,用于连接模板字面量片段中的已煮熟(转义后的)字符串值,将无标签模板的默认行为作为可调用 API 提供。它旨在通过提供一个内置的最终拼接步骤来简化自定义模板标签,避免重新实现逻辑或误用 String.raw。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    String.cooked 提案

    ** champions:**

    • Jamie Kyle (Rome)
    • Hemanth HM

    作者:

    • Darien Maillet Valentine

    阶段: 1 (跟踪问题)

    您可以浏览 ecmarkup 输出 或浏览 源代码

    概述

    这提出了一个新的静态 String 方法,类似于 String.raw,但它连接的是“已煮熟”(转义后的字符串值)字符串,而不是原始字符串——这与无标签模板字面量的行为相同。

    String.raw`consuming \u0072aw or undercooked strings may increase your risk of stringborne illness`;
    // → "consuming \u0072aw or undercooked strings may increase your risk of stringborne illness"
    
    String.cooked`mmm ... \u0064elicious cooked string`;
    // → "mmm ... delicious cooked string"

    这可以用来简化新模板字符串标签的创建:

    function myTag(strings, ...values) {
      return String.cooked(strings, ...values.map(value => String(value).toUpperCase())
    }
    
    myTag`hello ${'world'}` // "hello WORLD"

    动机

    许多模板标签对“已煮熟”的字符串值、替换值或两者进行某种预处理感兴趣——但最终在处理之后,它们可能仍希望执行“默认”的拼接行为。

    目前至少有两种方式可以实现这一点:

    1. 为字符串值和替换值“手动”实现类似“拉链”的拼接行为。
    2. 委托给 String.raw

    后者非常有吸引力;这是唯一暴露出来的、看起来像“默认”行为的东西。但它实际上不同并不太明显,因为对于大多数输入字符串,人们可能测试输出时结果是一样的;除非你输入包含转义序列(或“不可烹饪”的转义类序列)的字面片段,否则差异并不明显。raw 存在而“已煮熟”行为没有对应物,这造成了一个失败陷阱。

    委托给 raw 是可能的——但它需要将已煮熟的字符串 当作 原始字符串传递,即 String.raw({ raw: strs }, ...subs),而不是 String.raw(strs, ...subs)。虽然这有效,但间接性令人困惑;这里没有“真正”的原始字符串值。

    人们可能也会因为其他原因诱惑地使用 String.raw,仿佛它是一个真正的恒等函数,如 这条 Twitter 帖子 所示。同样,人们为什么可能认为这唯一的内置标签正是他们想要的,这似乎相当可以理解,但希望随着 cooked 的出现,这种区分将变得更加明显。

    使用场景

    主要使用场景是作为自定义模板标签的最终步骤,这些标签对输入执行某种映射。例如,考虑一个标签,旨在转义 URL 路径段,使其能够往返(即,插入部分中的任何 /?# 字符都被百分号编码):

    function safePath(strings, ...subs) {
      return String.cooked(strings, ...subs.map(sub => encodeURIComponent(sub)));
    }
    
    let id = 'spottie?';
    
    safePath`/cats/${ id }`;
    
    // → "/cats/spottie%3F"

    换句话说,虽然它具有模板标签函数的签名,但它主要预期是促进构建其他模板标签,而无需重新实现通常的字符串/替换拼接逻辑。

    作为标签本身,它的行为类似于恒等函数的模板标签等价物,这可能也有助于类似前面链接的用法模式,即用户希望使用模板标签向编辑器提供内容应解释为 HTML 的信号。一些编译或预处理工具也可能从中受益,例如 Prettier 对绑定为“html”的标签进行不同的字符串转换。

    问答

    名称应该是“cooked”吗?

    不确定!这是一个初步提案。关于这个名称是否直观清晰的反馈将很有帮助。该术语在讨论上下文(ES Discuss 等)中作为“raw”的对应词使用已有历史,但据我所知,至今尚未出现在任何规范文本或 API 表面。

    当从第一个参数对象读取属性时遇到 undefined,行为是什么?

    暂定提出的行为是,如果读取索引键属性时返回 undefined,则抛出 TypeError。对于任何其他类型的值,则尝试普通的 ToString 转换。

    这是因为(假设第一个参数是“真正的”模板数组对象)出现 undefined 表示原始片段源包含 NotEscapeSequence,即它是一个具有原始值但 没有 已煮熟值的模板。如果这样的模板字面量是 未标记的,则会抛出 SyntaxError(尽管这可能不适合求值时的 API,因此使用 TypeError)。

    可以说它可以改为对任何非字符串值抛出(不符合惯例),或者可以对 undefined 不抛出。当前提出行为的理由是它旨在平衡防止陷阱与其他人体工程学问题。