From c5b916c1543ce2023e6df75afa5f9c9d1f483b72 Mon Sep 17 00:00:00 2001 From: allo Date: Fri, 14 Jan 2022 14:13:32 +0800 Subject: sync with english version --- .../classes/private_class_fields/index.md | 314 ++++++++++++--------- 1 file changed, 181 insertions(+), 133 deletions(-) (limited to 'files/zh-cn/web/javascript/reference') 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 --- -
{{JsSidebar("Classes")}}
+{{JsSidebar("Classes")}} -

类属性在默认情况下是公共的,可以被外部类检测或修改。在ES2020 实验草案 中,增加了定义私有类字段的能力,写法是使用一个#作为前缀。

+类属性在默认情况下是{{jsxref('Classes/Public_class_fields','公有')}}的,但可以使用增加哈希前缀 `#` 的方法来定义私有类字段,这一隐秘封装的类特性由 JavaScript 自身强制执行。 -

语法

+## 语法 -
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;
 }
-
-

 例子

+class ClassWithPrivateStaticMethod { + static #privateStaticMethod() { + return 'hello world'; + } +} +``` + +## 示例 + +### 私有字段 + +私有字段包括私有实例字段和私有静态字段。 -

私有静态字段

+#### 私有实例字段 -

私有字段可以被类的构造方法(constructor)从内部声明。

+私有实例字段使用 `#名称`(发音为“哈希名称”)声明,这些名称以 `#` 开头。即 `#` 是名称本身的一部分,声明和访问时也需要加上。私有字段在类声明的构造方法中就可被访问。 -

静态变量只能被静态方法调用的限制仍然成立。

+从作用域之外引用 `#` 名称、内部在位声明的情况下引用私有字段、或尝试使用 `delete` 移除声明的字段都会抛出语法错误。 -
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)
+const instance = new ClassWithPrivateField() +instance.#privateField === 42; // 语法错误 +``` + +> **备注:** 可以使用 [`in`](/zh-CN/docs/Web/JavaScript/Reference/Operators/in) 运算符检查私有字段(或私有方法)是否存在。当私有字段或私有方法存在时,运算符返回 `true`,否则返回 `false`。 -

在类评估时,私有静态字段被添加到类构造函数中。

+类似于公有字段,私有字段在构造(construction)基类或调用子类的 `super()` 方法时被添加到类实例中。 -

私有静态字段有一个来源限制, 只有定义该私有静态字段的类能访问该字段。

+```js +class ClassWithPrivateField { + #privateField; -

这可能会导致:当使用this时出现意想不到的行为。

+ constructor() { + this.#privateField = 42; + } +} -
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)
-
+#### 私有静态字段 -

私有实例字段

+私有静态字段在解析类结构时被添加到类的构造方法(constructor)中。且静态变量只能被静态方法调用的限制仍然成立。 -

私有实例字段使用 #名称(发音为“哈希名称”)声明,这些名称以 #开头。  #是名称本身的一部分, 声明和访问时也需要加上。

+```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 +``` -

封装由语言强制执行。 从作用域之外引用#名称是语法错误。

+私有静态字段有一个来源限制:只有定义该私有静态字段的类能访问该字段。使用 **`this`** 可能会出现意想不到的行为。在下方的例子中,`this` 是 `SubClass` 类(而不是 `BaseClassWithPrivateStaticField` 类)的引用,所以尝试调用 `SubClass.basePublicStaticMethod()` 会抛出 `TypeError`。 -
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
-
+class SubClass extends BaseClassWithPrivateStaticField { }; + +let error = null; -

私有方法

+try { + SubClass.basePublicStaticMethod() +} catch(e) { error = e}; -

私有静态方法

+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 +``` -

像它们的公有等价方法一样,私有静态方法是在类本身而非类的实例上调用的。 像私有静态字段一样,只能从类声明内部访问它们。

+### 私有方法 -

私有静态方法可能是生成器方法,异步方法和异步生成器方法。

+#### 私有实例方法 -
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);
-
- -

使用this可能会导致意想不到的行为(因为this绑定规则适用)。

- -
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
-
+#### 私有静态方法 -

私有实例方法

+像它们的公有等价方法一样,私有静态方法是在类本身而非类的实例上调用的。像私有静态字段一样,只能从类声明内部访问它们。 -

私有实例方法是类实例上可用的方法,它们的访问方式与私有实例字段相同。

+```js +class ClassWithPrivateStaticMethod { + static #privateStaticMethod() { + return 42; + } -
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 worl​d"
+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(); + } +} -

私有实例方法可以是生成器方法,异步方法或异步生成器方法。 私有的getter和setter也是可能的:

+class Derived extends Base {} -
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 worl​d✨"
-
- -

规范

- - - - - - - - - - - - -
Specification
{{SpecName('Public and private instance fields', '#prod-FieldDefinition', 'FieldDefinition')}}
- -

浏览器兼容性

- -

{{Compat("javascript.classes.private_class_fields")}}

- -

相关链接

- - +## 浏览器兼容性 + +{{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 -- cgit v1.2.3-54-g00ecf