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-private-fields-in-in.md.
  • 简体中文
  • Ergonomic brand checks for Private Fields S4

    中文标题:私有字段的人体工程学品牌检查

    提案概览
    提案速览

    该提案解决了在不抛出异常的情况下检查对象是否具有私有字段的问题,目前需要使用笨拙的 try/catch 模式。主要解决方案引入了 in 运算符来测试私有字段的存在性,例如 #brand in obj

    Note

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

    私有字段的人体工程学品牌检查

    EcmaScript 提案、规范和参考实现,用于提供无异常的品牌检查。

    规范由 @ljharb 起草。

    基于 https://github.com/tc39/ecma262/pull/1668/ 构建,等待类字段进入第 4 阶段并合并到更大的规范中。

    该提案目前处于 流程 的第 4 阶段。

    理由

    私有字段内置了“品牌检查”,即如果你尝试在未安装该私有字段的对象上访问私有字段,它会抛出异常。

    这很好!但是,为了真正保持私有字段的存在性,我经常需要检查对象是否具有私有字段,如果没有,则有一些回退行为(甚至可能抛出自定义异常,该异常的消息不会泄露我使用私有字段作为机制的事实)。

    为此使用 try/catch 确实可行,但相当笨拙:

    class C {
      #brand;
    
      static isC(obj) {
        try {
          obj.#brand;
          return true;
        } catch {
          return false;
        }
      }
    }

    这对于 getter(可能抛出异常)来说也是一个问题:

    class C {
      #data = null; // 稍后填充
    
      get #getter() {
        if (!this.#data) {
          throw new Error('no data yet!');
        }
        return this.#data;
      }
    
      static isC(obj) {
        try {
          obj.#getter;
          return true;
        } catch {
          return false; // 糟糕!可能因为 `#getter` 抛出异常而到达这里 :-(
        }
      }
    }

    所期望的是一个简单的解决方案,用于生成表示私有字段是否存在的布尔值,而不需要 try/catch 或异常。

    解决方案:

    in

    最明显的解决方案是使用 in 关键字,如下所示:

    class C {
      #brand;
    
      #method() {}
    
      get #getter() {}
    
      static isC(obj) {
        return #brand in obj && #method in obj && #getter in obj;
      }
    }

    这没有我所知的 ASI 风险;然而,它有一个重要的权衡:它永久地扼杀了私有字段简写的任何可能性。具体来说,这是因为如果 #brand(在前面的例子中)是 this.#brand 的简写,那么 (#brand) in obj 必须与 this.#brand in obj 相同,这意味着“this.#brand 的_值_是否在 obj 中?”,而不是“obj 是否具有私有字段 #brand?”。

    被拒绝的解决方案:

    try 语句

    另一种替代方案是:

    class C {
      #brand;
    
      static isC(obj) {
        return try obj.#brand;
      }
    }

    然而,这强烈暗示 try <expression> 将是一种通用语法,表示“如果它抛出异常,产生 false,否则产生 true”。那将是一个更大的提案,并且对于解决私有字段的具体问题来说可能有点过头了。

    这将需要对花括号进行前瞻限制(这意味着 try 表达式不能是对象字面量,除非用括号括起来)。

    规范

    您可以查看 in 解决方案的规范,渲染为 HTML

    实现