diff options
author | allo <yin199909@aliyun.com> | 2022-01-14 14:13:32 +0800 |
---|---|---|
committer | Irvin <irvinfly@gmail.com> | 2022-01-19 01:06:50 +0800 |
commit | c5b916c1543ce2023e6df75afa5f9c9d1f483b72 (patch) | |
tree | d2200a07e6bac0f12a71c551a45444ef346acda9 /files | |
parent | 453c75d5569131fce201fba3fd1849c338ae117e (diff) | |
download | translated-content-c5b916c1543ce2023e6df75afa5f9c9d1f483b72.tar.gz translated-content-c5b916c1543ce2023e6df75afa5f9c9d1f483b72.tar.bz2 translated-content-c5b916c1543ce2023e6df75afa5f9c9d1f483b72.zip |
sync with english version
Diffstat (limited to 'files')
-rw-r--r-- | files/zh-cn/web/javascript/reference/classes/private_class_fields/index.md | 314 |
1 files changed, 181 insertions, 133 deletions
diff --git a/files/zh-cn/web/javascript/reference/classes/private_class_fields/index.md b/files/zh-cn/web/javascript/reference/classes/private_class_fields/index.md index 70803df8a1..34074a550a 100644 --- a/files/zh-cn/web/javascript/reference/classes/private_class_fields/index.md +++ b/files/zh-cn/web/javascript/reference/classes/private_class_fields/index.md @@ -7,193 +7,241 @@ tags: - 语言特性 translation_of: Web/JavaScript/Reference/Classes/Private_class_fields --- -<div>{{JsSidebar("Classes")}}</div> +{{JsSidebar("Classes")}} -<p>类属性在默认情况下是公共的,可以被外部类检测或修改。在<a href="https://github.com/tc39/proposal-class-fields">ES2020 实验草案</a> 中,增加了定义私有类字段的能力,写法是使用一个#作为前缀。</p> +类属性在默认情况下是{{jsxref('Classes/Public_class_fields','公有')}}的,但可以使用增加哈希前缀 `#` 的方法来定义私有类字段,这一隐秘封装的类特性由 JavaScript 自身强制执行。 -<h2 id="语法">语法</h2> +## 语法 -<pre class="brush: js notranslate">class ClassWithPrivateField { - #privateField +```js +class ClassWithPrivateField { + #privateField; } class ClassWithPrivateMethod { #privateMethod() { - return 'hello world' - } + return 'hello world'; + } } class ClassWithPrivateStaticField { - static #PRIVATE_STATIC_FIELD + static #PRIVATE_STATIC_FIELD; } -</pre> -<h2 id="例子"> 例子</h2> +class ClassWithPrivateStaticMethod { + static #privateStaticMethod() { + return 'hello world'; + } +} +``` + +## 示例 + +### 私有字段 + +私有字段包括私有实例字段和私有静态字段。 -<h3 id="私有静态字段">私有静态字段</h3> +#### 私有实例字段 -<p>私有字段可以被类的构造方法(constructor)从内部声明。</p> +私有实例字段使用 `#名称`(发音为“哈希名称”)声明,这些名称以 `#` 开头。即 `#` 是名称本身的一部分,声明和访问时也需要加上。私有字段在类声明的构造方法中就可被访问。 -<p>静态变量只能被静态方法调用的限制仍然成立。</p> +从作用域之外引用 `#` 名称、内部在位声明的情况下引用私有字段、或尝试使用 `delete` 移除声明的字段都会抛出语法错误。 -<pre class="brush: js notranslate">class ClassWithPrivateStaticField { - static #PRIVATE_STATIC_FIELD +```js example-bad +class ClassWithPrivateField { + #privateField; - static publicStaticMethod() { - ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42 - return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD - } + constructor() { + this.#privateField = 42; + delete this.#privateField; // 语法错误 + this.#undeclaredField = 444; // 语法错误 + } } -assert(ClassWithPrivateStaticField.publicStaticMethod() === 42)</pre> +const instance = new ClassWithPrivateField() +instance.#privateField === 42; // 语法错误 +``` + +> **备注:** 可以使用 [`in`](/zh-CN/docs/Web/JavaScript/Reference/Operators/in) 运算符检查私有字段(或私有方法)是否存在。当私有字段或私有方法存在时,运算符返回 `true`,否则返回 `false`。 -<p>在类评估时,私有静态字段被添加到类构造函数中。</p> +类似于公有字段,私有字段在构造(construction)基类或调用子类的 `super()` 方法时被添加到类实例中。 -<p>私有静态字段有一个来源限制, 只有定义该私有静态字段的类能访问该字段。</p> +```js +class ClassWithPrivateField { + #privateField; -<p>这可能会导致:当使用<strong><code>this</code></strong>时出现意想不到的行为。</p> + constructor() { + this.#privateField = 42; + } +} -<pre class="brush: js notranslate">class BaseClassWithPrivateStaticField { - static #PRIVATE_STATIC_FIELD +class SubClass extends ClassWithPrivateField { + #subPrivateField; - static basePublicStaticMethod() { - this.#PRIVATE_STATIC_FIELD = 42 - return this.#PRIVATE_STATIC_FIELD - } + constructor() { + super(); + this.#subPrivateField = 23; + } } -class SubClass extends BaseClassWithPrivateStaticField { } +new SubClass(); +// SubClass {#privateField: 42, #subPrivateField: 23} +``` -assertThrows(() => SubClass.basePublicStaticMethod(), TypeError) -</pre> +#### 私有静态字段 -<h3 id="私有实例字段">私有实例字段</h3> +私有静态字段在解析类结构时被添加到类的构造方法(constructor)中。且静态变量只能被静态方法调用的限制仍然成立。 -<p>私有实例字段使用 <strong>#名称</strong>(发音为“哈希名称”)声明,这些名称以 <code>#</code>开头。 <code>#</code>是名称本身的一部分, 声明和访问时也需要加上。</p> +```js +class ClassWithPrivateStaticField { + static #PRIVATE_STATIC_FIELD; + + static publicStaticMethod() { + ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42; + return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD; + } +} + +console.log(ClassWithPrivateStaticField.publicStaticMethod() === 42); +// true +``` -<p>封装由语言强制执行。 从作用域之外引用#名称是语法错误。</p> +私有静态字段有一个来源限制:只有定义该私有静态字段的类能访问该字段。使用 **`this`** 可能会出现意想不到的行为。在下方的例子中,`this` 是 `SubClass` 类(而不是 `BaseClassWithPrivateStaticField` 类)的引用,所以尝试调用 `SubClass.basePublicStaticMethod()` 会抛出 `TypeError`。 -<pre class="brush: js notranslate">class ClassWithPrivateField { - #privateField +```js +class BaseClassWithPrivateStaticField { + static #PRIVATE_STATIC_FIELD; - constructor() { - this.#privateField = 42 - this.#randomField = 666 // Syntax error - } + static basePublicStaticMethod() { + this.#PRIVATE_STATIC_FIELD = 42; + return this.#PRIVATE_STATIC_FIELD; + } } -const instance = new ClassWithPrivateField() -instance.#privateField === 42 // Syntax error -</pre> +class SubClass extends BaseClassWithPrivateStaticField { }; + +let error = null; -<h3 id="私有方法">私有方法</h3> +try { + SubClass.basePublicStaticMethod() +} catch(e) { error = e}; -<h4 id="私有静态方法">私有静态方法</h4> +console.log(error instanceof TypeError); +// true +console.log(error); +// TypeError: Cannot write private member #PRIVATE_STATIC_FIELD +// to an object whose class did not declare it +``` -<p>像它们的公有等价方法一样,私有静态方法是在类本身而非类的实例上调用的。 像私有静态字段一样,只能从类声明内部访问它们。</p> +### 私有方法 -<p>私有静态方法可能是生成器方法,异步方法和异步生成器方法。</p> +#### 私有实例方法 -<pre class="brush: js notranslate">class ClassWithPrivateStaticMethod { - static #privateStaticMethod() { - return 42 - } +私有实例方法是类实例上可用的方法,它们的访问方式与私有实例字段相同。 - static publicStaticMethod1() { - return ClassWithPrivateStaticMethod.#privateStaticMethod(); - } +```js +class ClassWithPrivateMethod { + #privateMethod() { + return 'hello world'; + } - static publicStaticMethod2() { - return this.#privateStaticMethod(); - } + getPrivateMessage() { + return this.#privateMethod(); + } } -assert(ClassWithPrivateStaticField.publicStaticMethod1() === 42); -assert(ClassWithPrivateStaticField.publicStaticMethod2() === 42); -</pre> - -<p>使用<strong><code>this</code></strong>可能会导致意想不到的行为(因为<code>this</code>绑定规则适用)。</p> - -<pre class="brush: js notranslate">class Base { - static #privateStaticMethod() { - return 42; - } - static publicStaticMethod1() { - return Base.#privateStaticMethod(); - } - static publicStaticMethod2() { - return this.#privateStaticMethod(); - } +const instance = new ClassWithPrivateMethod(); +console.log(instance.getPrivateMessage()); +// hello world +``` + +私有实例方法可以是生成器方法、异步方法或异步生成器方法,也可以是私有的 getter 和 setter。 + +```js +class ClassWithPrivateAccessor { + #message; + + get #decoratedMessage() { + return `🎬${this.#message}🛑`; + } + set #decoratedMessage(msg) { + this.#message = msg; + } + + constructor() { + this.#decoratedMessage = 'hello world'; + console.log(this.#decoratedMessage); + } } -class Derived extends Base {} +new ClassWithPrivateAccessor(); +// 🎬hello world🛑 +``` -console.log(Derived.publicStaticMethod1()); // 42 -console.log(Derived.publicStaticMethod2()); // TypeError -</pre> +#### 私有静态方法 -<h4 id="私有实例方法">私有实例方法</h4> +像它们的公有等价方法一样,私有静态方法是在类本身而非类的实例上调用的。像私有静态字段一样,只能从类声明内部访问它们。 -<p>私有实例方法是类实例上可用的方法,它们的访问方式与私有实例字段相同。</p> +```js +class ClassWithPrivateStaticMethod { + static #privateStaticMethod() { + return 42; + } -<pre class="brush: js notranslate">class ClassWithPrivateMethod { - #privateMethod() { - return 'hello world' - } + static publicStaticMethod1() { + return ClassWithPrivateStaticMethod.#privateStaticMethod(); + } - getPrivateMessage() { - return this.#privateMethod() - } + static publicStaticMethod2() { + return this.#privateStaticMethod(); + } } -const instance = new ClassWithPrivateMethod() -console.log(instance.getPrivateMessage()) -// expected output: "hello world"</pre> +console.log(ClassWithPrivateStaticMethod.publicStaticMethod1() === 42); +// true +console.log(ClassWithPrivateStaticMethod.publicStaticMethod2() === 42); +// true +``` + +私有静态方法可以是生成器方法,异步方法或异步生成器方法。 + +前面提到的私有静态字段的限制同样适用于私有静态方法。同样地,使用 **`this`** 可能会出现意想不到的行为。在下方的例子中,`this` 是 `Derived` 类(而不是 `Base` 类)的引用,所以尝试调用 `Derived.publicStaticMethod2()` 会抛出 `TypeError`。 + +```js +class Base { + static #privateStaticMethod() { + return 42; + } + static publicStaticMethod1() { + return Base.#privateStaticMethod(); + } + static publicStaticMethod2() { + return this.#privateStaticMethod(); + } +} -<p>私有实例方法可以是生成器方法,异步方法或异步生成器方法。 私有的getter和setter也是可能的:</p> +class Derived extends Base {} -<pre class="brush: js notranslate">class ClassWithPrivateAccessor { - #message +console.log(Derived.publicStaticMethod1()); +// 42 +console.log(Derived.publicStaticMethod2()); +// TypeError: Cannot read private member #privateStaticMethod +// from an object whose class did not declare it +``` - get #decoratedMessage() { - return `✨${this.#message}✨` - } - set #decoratedMessage(msg) { - this.#message = msg - } +## 规范 - constructor() { - this.#decoratedMessage = 'hello world' - console.log(this.#decoratedMessage) - } -} +{{Specifications("javascript.classes")}} -new ClassWithPrivateAccessor(); -// expected output: "✨hello world✨" -</pre> - -<h2 id="规范">规范</h2> - -<table class="standard-table"> - <thead> - <tr> - <th scope="col">Specification</th> - </tr> - </thead> - <tbody> - <tr> - <td>{{SpecName('Public and private instance fields', '#prod-FieldDefinition', 'FieldDefinition')}}</td> - </tr> - </tbody> -</table> - -<h2 id="浏览器兼容性">浏览器兼容性</h2> - -<p>{{Compat("javascript.classes.private_class_fields")}}</p> - -<h2 id="相关链接">相关链接</h2> - -<ul> - <li><a href="/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields">Public class fields</a></li> - <li><a href="https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html">The Semantics of All JS Class Elements</a></li> -</ul> +## 浏览器兼容性 + +{{Compat("javascript.classes")}} + +## 参见 + +- [Working with private class features](/en-US/docs/Web/JavaScript/Guide/Working_With_Private_Class_Features) +- [Public class fields](/zh-CN/docs/Web/JavaScript/Reference/Classes/Public_class_fields) +- [The + Semantics of All JS Class Elements](https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html) +- [Public and private class fields](https://v8.dev/features/class-fields) + article at the v8.dev site |