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-throw-expressions.md.
  • 简体中文
  • throw expressions S2

    中文标题:throw 表达式

    提案概览
    提案速览

    该提案引入了 throw 表达式,允许在参数初始化器、箭头函数和条件表达式等表达式上下文中抛出异常。它与 throw 语句在优先级上存在差异,因此禁止其右侧出现某些二元运算符,除非用括号括起来。

    Note

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

    ECMAScript throw 表达式

    本提案定义了在表达式上下文中抛出异常的新语法。

    状态

    阶段: 2
    提案发起人: Ron Buckton (@rbuckton)

    更多信息请参见 TC39 提案流程

    作者

    • Ron Buckton (@rbuckton)

    提案

    throw 表达式允许你在表达式上下文中抛出异常。例如:

    • 参数初始化器
      function save(filename = throw new TypeError("Argument required")) {
      }
    • 箭头函数体
      lint(ast, { 
        with: () => throw new Error("avoid using 'with' statements.")
      });
    • 条件表达式
      function getEncoder(encoding) {
        const encoder = encoding === "utf8" ? new UTF8Encoder() 
                      : encoding === "utf16le" ? new UTF16Encoder(false) 
                      : encoding === "utf16be" ? new UTF16Encoder(true) 
                      : throw new Error("Unsupported encoding");
      }
    • 逻辑运算
      class Product {
        get id() { return this._id; }
        set id(value) { this._id = value || throw new Error("Invalid value"); }
      }

    throw 表达式 不会 替换 throw 语句,因为它们的值的优先级不同。为了保持 throw 语句的优先级, 我们必须对 ExpressionStatement 添加一个前瞻限制以避免歧义。

    由于 throw 表达式和 ThrowStatement 之间的优先级不同,表达式右侧的某些运算符可能以不同的方式解析,这可能导致歧义和混乱:

    throw a ? b : c; // 计算 'a',抛出 'b' 或 'c'
    (throw a ? b : c); // 在没有限制的情况下,会抛出 'a',所以 `?` 被禁止
    
    throw a, b; // 计算 'a',抛出 'b'
    (throw a, b); // 会抛出 'a',而非 'b',所以 `,` 被禁止
    
    throw a && b; // 如果 'a' 为假,抛出 'a',否则抛出 'b'
    (throw a && b); // 总是抛出 'a',所以 `&&` 被禁止
    
    throw a || b; // 如果 'a' 为真,抛出 'a',否则抛出 'b'
    (throw a || b); // 总是抛出 'a',所以 `||` 被禁止
    
    // ... 等等

    因此,所有二元运算符以及 ? 运算符都被禁止出现在 throw 表达式的右侧。要在 throw 表达式中使用这些运算符,表达式必须用括号括起来:

    (throw (a, b)); // 计算 'a',抛出 'b'
    (throw (a ? b : c)); // 计算 'a',抛出 'b' 或 'c'

    但是,我们没有禁止 :,这样 throw 表达式仍然可以方便地在三元表达式中使用:

    const x = a ? throw b : c; // 如果 'a' 为真则抛出 'b',否则计算 'c'

    语法

    ++ThrowExpressionInvalidPunctuator : one of
      `,` `<` `>` `<=` `>=` `==` `!=` `===` `!==` `+` `-` `*` `/` `%` `**` `<<` `>>` `>>>` `&` `|` `^` `&&` `||` `??`
      `=` `+=` `-=` `*=` `%=` `**=` `<<=` `>>=` `>>>=` `&=` `|=` `^=` `&&=` `||=` `??=` `?`
    
      UnaryExpression[Yield, Await] :
    ++  `throw` UnaryExpression[?Yield, ?Await] [lookahead ∉ ThrowExpressionInvalidPunctuator]
    
      ExpressionStatement[Yield, Await] :
    --  [lookahead ∉ {`{`, `function`, `async` [no |LineTerminator| here] `function`, `class`, `let [`}] Expression[+In, ?Yield, ?Await] `;`
    ++  [lookahead ∉ {`{`, `function`, `async` [no |LineTerminator| here] `function`, `class`, `let [`, `throw`}] Expression[+In, ?Yield, ?Await] `;`

    其他说明

    可以使用类似如下的定义在 ECMAScript 中近似实现 throw 表达式:

    const __throw = err => { throw err; };
    
    // 通过辅助函数...
    function getEncoder1(encoding) {
      const encoder = encoding === "utf8" ? new UTF8Encoder() 
                    : encoding === "utf16le" ? new UTF16Encoder(false) 
                    : encoding === "utf16be" ? new UTF16Encoder(true) 
                    : __throw(new Error("Unsupported encoding"));
    }
    
    // 通过箭头函数...
    function getEncoder2(encoding) {
      const encoder = encoding === "utf8" ? new UTF8Encoder() 
                    : encoding === "utf16le" ? new UTF16Encoder(false) 
                    : encoding === "utf16be" ? new UTF16Encoder(true) 
                    : (() => { throw new Error("Unsupported encoding"); })();
    }

    然而,与原生实现相比,这有几个缺点:

    • __throw 辅助函数会出现在宿主环境中的 err.stack 中。
      • 某些 具有 Error.captureStackTrace 的宿主中,这可以得到缓解。
    • 宿主需要更多信息来进行优化/去优化决策,因为 throw 不在函数内部。
    • 不利于调试,因为引发异常的帧位于辅助函数内部。
    • 内联调用的箭头函数不便于使用(与原生相比,至少多 10 个符号)。

    资源

    待办事项

    以下是推进 TC39 提案流程 各个阶段的高级任务列表:

    第 1 阶段入口标准

    • 确定了一位“提案发起人”来推进该添加。
    • 概述问题或需求以及解决方案大致形态的说明
    • 说明性示例用法。
    • 高级 API (提案不引入 API)

    第 2 阶段入口标准

    第 3 阶段入口标准

    第 4 阶段入口标准