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-declarations.md.
  • 简体中文
  • Private declarations S1

    中文标题:私有声明

    提案概览
    提案速览

    该提案引入了私有声明,允许类词法作用域外部的可信代码访问私有状态。它支持为子类提供受保护状态、通过友元函数进行受控访问,以及在非类对象工厂上使用私有字段。

    Note

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

    私有声明

    一项提案,用于添加私有声明,允许类词法作用域 外部 的可信代码访问私有状态。

    private #hello;
    class Example {
      outer #hello = 'world!';
    
      hello() {
        return this.#hello;
      }
    }
    
    const ex = new Example();
    console.log(ex.hello()); // => 'world!'
    console.log(ex.#hello); // => 'world!'

    这还允许我们将私有状态引入普通对象!

    private #hello;
    function Example() {
      return {
        outer #hello: 'world',
    
        hello() {
          return this.#hello;
        }
      }
    }
    
    const ex = Example();
    console.log(ex.hello()); // => 'world!'
    console.log(ex.#hello); // => 'world!'

    可能的后续提案可以允许将私有声明共享给友好的模块。

    支持者

    状态

    当前阶段: 1

    指导性用例

    “受保护”状态

    在实现类层级时,受保护状态是一种有价值的可见性状态。例如,可以使用钩子模式允许子类覆盖代码:

    // https://github.com/Polymer/lit-html/blob/1a51eb54/src/lib/parts.ts
    
    private #createPart;
    
    class AttributeCommitter {
      //...
    
      outer #createPart() {
        return new AttributePart(this);
      }
    }
    
    class PropertyCommitter extends AttributeCommitter {
      outer #createPart() {
        return new PropertyPart(this);
      }
    }

    这里,AttributeCommitter 明确允许可信的(写在同一个源文件中的)子类覆盖 #createPart 方法的行为。默认情况下,返回普通的 AttributePart。但 PropertyCommitter 仅处理属性,会返回 PropertyPart。所有其他代码都可以通过 AttributeCommitter 的正常公开可见的字段/方法进行继承。

    注意,这并不会授予文件外部代码覆盖 #createPart 方法的权限,因为 #createPart 私有声明仅在其声明的作用域内可见。

    友元类/函数

    有关 C++ 中的先例,请参见 https://en.wikipedia.org/wiki/Friend_function。

    AMP 项目有一种特定的分阶段 lint 模式,非常适合用于保护受限代码访问的友元函数。首先,静态使用的函数比对象作用域的方法调用更容易进行 lint 检查,因为我们不需要知道对象的类型。因此,判断这是受限调用还是使用相同方法名的非受限调用要容易得多。例如,更容易看出静态导出 registerExtendedTemplate 是受限的,而 obj.registerExtendedTemplate 不是。

    // https://github.com/ampproject/amphtml/blob/18baa9da/src/service/template-impl.js
    
    private #registerTemplate;
    
    // 导出以便可以安装在全局上,并在拆分的包之间共享。
    export class Templates {
      outer #registerTemplate() {
        //...
      }
    }
    
    // 有权向共享类实例注册模板的代码。导入并使用它是静态可分析的,并且必须通过 lint 检查。
    export function registerExtendedTemplate() {
      const templatesService = getService('templates');
      return templatesService.#registerTemplate(...arguments);
    }

    非类对象工厂

    并非所有代码都希望使用 class。有时您仍然希望在这种情况下拥有私有字段。

    private #hash;
    
    export function factory(value) {
      return Object.freeze({
        value,
        outer #hash: someFunction(value),
      });
    }
    
    export function isProducedByMyFactory(value) {
      return #hash in value;
    }
    
    export function equals(a, b) {
      if (a.#hash !== b.#hash) return false;
      return expensiveCompare(a.value, b.value);
    }