From 310fd066e91f454b990372ffa30e803cc8120975 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:56:40 +0100 Subject: unslug zh-cn: move --- .../classes/public_class_fields/index.html | 352 +++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 files/zh-cn/web/javascript/reference/classes/public_class_fields/index.html (limited to 'files/zh-cn/web/javascript/reference/classes/public_class_fields/index.html') diff --git a/files/zh-cn/web/javascript/reference/classes/public_class_fields/index.html b/files/zh-cn/web/javascript/reference/classes/public_class_fields/index.html new file mode 100644 index 0000000000..fb8c618a9b --- /dev/null +++ b/files/zh-cn/web/javascript/reference/classes/public_class_fields/index.html @@ -0,0 +1,352 @@ +--- +title: 类元素 +slug: Web/JavaScript/Reference/Classes/Class_elements +tags: + - Class + - JavaScript + - 类 +translation_of: Web/JavaScript/Reference/Classes/Public_class_fields +--- +
{{JsSidebar("Classes")}}
+ +
公有(public)和私有(private)字段声明是一个JavaScript标准委员会TC39提议的试验性功能 (第3阶段)。这项功能在浏览器中的支持还受限,但你可以通过Babel等构建系统来使用它。参见下面的兼容性信息
+ +

公有字段

+ +

静态公有字段和实例公有字段都是可编辑的,可遍历的,可配置的。它们本身不同于私有对应值(private counterparts)的是,它们参与原型的继承。

+ +

静态公有字段

+ +

静态公有字段在你想要创建一个只在每个类里面只存在一份,而不会存在于你创建的每个类的实例中的属性时可以用到。你可以用它存放缓存数据、固定结构数据或者其他你不想在所有实例都复制一份的数据。

+ +

静态公有字段是使用关键字 static 声明的。我们在声明一个类的时候,使用Object.defineProperty方法将静态公有字段添加到类的构造函数中。在类被声明之后,可以从类的构造函数访问静态公有字段。

+ +
class ClassWithStaticField {
+  static staticField = 'static field';
+}
+
+console.log(ClassWithStaticField.staticField);
+// 预期输出值: "static field"​
+
+ +

没有设定初始化程序的字段将默认被初始化为undefined

+ +
class ClassWithStaticField {
+  static staticField;
+}
+
+console.assert(ClassWithStaticField.hasOwnProperty('staticField'));
+console.log(ClassWithStaticField.staticField);
+// 预期输出值: "undefined"
+ +

静态公有字段不会在子类里重复初始化,但我们可以通过原型链访问它们。

+ +
class ClassWithStaticField {
+  static baseStaticField = 'base field';
+}
+
+class SubClassWithStaticField extends ClassWithStaticField {
+  static subStaticField = 'sub class field';
+}
+
+console.log(SubClassWithStaticField.subStaticField);
+// 预期输出值: "sub class field"
+
+console.log(SubClassWithStaticField.baseStaticField);
+// 预期输出值: "base field"
+ +

当初始化字段时,this指向的是类的构造函数。你可以通过名字引用构造函数,并使用super获取到存在的超类构造函数。

+ +
class ClassWithStaticField {
+  static baseStaticField = 'base static field';
+  static anotherBaseStaticField = this.baseStaticField;
+
+  static baseStaticMethod() { return 'base static method output'; }
+}
+
+class SubClassWithStaticField extends ClassWithStaticField {
+  static subStaticField = super.baseStaticMethod();
+}
+
+console.log(ClassWithStaticField.anotherBaseStaticField);
+// 预期输出值: "base static field"
+
+console.log(SubClassWithStaticField.subStaticField);
+// 预期输出值: "base static method output"
+
+ +

公有实例字段

+ +

公有实例字段存在于类的每一个实例中。通过声明一个公有字段,我们可以确保该字段一直存在,而类的定义则会更加像是自我描述。

+ +

公有实例字段可以在基类的构造过程中(构造函数主体运行前)使用Object.defineProperty添加,也可以在子类构造函数中的super()函数结束后添加。

+ +
class ClassWithInstanceField {
+  instanceField = 'instance field';
+}
+
+const instance = new ClassWithInstanceField();
+console.log(instance.instanceField);
+// 预期输出值: "instance field"
+ +

没有设定初始化程序的字段将默认被初始化为undefined

+ +
class ClassWithInstanceField {
+  instanceField;
+}
+
+const instance = new ClassWithInstanceField();
+console.assert(instance.hasOwnProperty('instanceField'));
+console.log(instance.instanceField);
+// 预期输出值: "undefined"
+ +

和属性(properties)一样,字段名可以由计算得出。

+ +
const PREFIX = 'prefix';
+
+class ClassWithComputedFieldName {
+    [`${PREFIX}Field`] = 'prefixed field';
+}
+
+const instance = new ClassWithComputedFieldName();
+console.log(instance.prefixField);
+// 预期输出值: "prefixed field"
+ +

当初始化字段时,this指向的是类正在构造中的实例。和公共实例方法相同的是:你可以在子类中使用super来访问超类的原型。

+ +
class ClassWithInstanceField {
+  baseInstanceField = 'base field';
+  anotherBaseInstanceField = this.baseInstanceField;
+  baseInstanceMethod() { return 'base method output'; }
+}
+
+class SubClassWithInstanceField extends ClassWithInstanceField {
+  subInstanceField = super.baseInstanceMethod();
+}
+
+const base = new ClassWithInstanceField();
+const sub = new SubClassWithInstanceField();
+
+console.log(base.anotherBaseInstanceField);
+// 预期输出值: "base field"
+
+console.log(sub.subInstanceField);
+// 预期输出值: "base method output"
+ +

公共方法

+ +

静态公共方法

+ +

关键字static将为一个类定义一个静态方法。静态方法不会在实例中被调用,而只会被类本身调用。它们经常是工具函数,比如用来创建或者复制对象。

+ +

{{EmbedInteractiveExample("pages/js/classes-static.html")}}

+ + + +

静态方法是在类的赋值阶段用Object.defineProperty方法添加到类中的。静态方法是可编辑的、不可遍历的和可配置的。

+ +

公共实例方法

+ +

正如其名,公共实例方法是可以在类的实例中使用的。

+ +
class ClassWithPublicInstanceMethod {
+  publicMethod() {
+    return 'hello world';
+  }
+}
+
+const instance = new ClassWithPublicInstanceMethod();
+console.log(instance.publicMethod());
+// 预期输出值: "hello worl​d"
+ +

公共实例方法是在类的赋值阶段用Object.defineProperty方法添加到类中的。静态方法是可编辑的、不可遍历的和可配置的。

+ +

你可以使用生成器(generator)、异步和异步生成器方法。

+ +
class ClassWithFancyMethods {
+  *generatorMethod() { }
+  async asyncMethod() { }
+  async *asyncGeneratorMethod() { }
+}
+ +

在实例的方法中,this指向的是实例本身,你可以使用super访问到超类的原型,由此你可以调用超类的方法。

+ +
class BaseClass {
+  msg = 'hello world';
+  basePublicMethod() {
+    return this.msg;
+  }
+}
+
+class SubClass extends BaseClass {
+  subPublicMethod() {
+    return super.basePublicMethod();
+  }
+}
+
+const instance = new SubClass();
+console.log(instance.subPublicMethod());
+// 预期输出值: "hello worl​d"
+
+ +

gettersetter是和类的属性绑定的特殊方法,分别会在其绑定的属性被取值、赋值时调用。使用getset句法定义实例的公共gettersetter

+ +
class ClassWithGetSet {
+  #msg = 'hello world';
+  get msg() {
+    return this.#msg;
+  }
+  set msg(x) {
+    this.#msg = `hello ${x}`;
+  }
+}
+
+const instance = new ClassWithGetSet();
+console.log(instance.msg);
+// expected output: "hello worl​d"
+
+instance.msg = 'cake';
+console.log(instance.msg);
+// 预期输出值: "hello cake"
+
+ +

私有字段

+ +

静态私有字段

+ +

静态私有字段可以在类声明本身内部的构造函数上被访问到。

+ +

静态变量只能被静态方法访问的限制依然存在。

+ +
class ClassWithPrivateStaticField {
+  static #PRIVATE_STATIC_FIELD;
+
+  static publicStaticMethod() {
+    ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42;
+    return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD;
+  }
+}
+
+assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);
+ +

静态私有字段是在类赋值的时候被添加到类构造函数中的。

+ +

静态私有字段有一个来源限制。只有定义静态私有字段的类可以访问该字段。这在使用this时,可能会导致不符合预期的行为。

+ +
class BaseClassWithPrivateStaticField {
+  static #PRIVATE_STATIC_FIELD;
+
+  static basePublicStaticMethod() {
+    this.#PRIVATE_STATIC_FIELD = 42;
+    return this.#PRIVATE_STATIC_FIELD;
+  }
+}
+
+class SubClass extends BaseClassWithPrivateStaticField { }
+
+assertThrows(() => SubClass.basePublicStaticMethod(), TypeError);
+
+ +

私有实例字段

+ +

私有实例字段是通过# names句型(读作“哈希名称”)声明的,即为识别符加一个前缀“#”。“#”是名称的一部分,也用于访问和声明。

+ +

封装是语言强制实施的。引用不在作用域内的 # names 是语法错误。

+ +
class ClassWithPrivateField {
+  #privateField;
+
+  constructor() {
+    this.#privateField = 42;
+    this.#randomField = 666; # Syntax error
+  }
+}
+
+const instance = new ClassWithPrivateField();
+instance.#privateField === 42; // Syntax error
+
+ +

私有方法

+ +

静态私有方法

+ +

和静态公共方法一样,静态私有方法也是在类里面而非实例中调用的。和静态私有字段一样,它们也只能在类的声明中访问。

+ +

你可以使用生成器(generator)、异步和异步生成器方法。

+ +

静态私有方法可以是生成器、异步或者异步生成器函数。

+ +
class ClassWithPrivateStaticMethod {
+    static #privateStaticMethod() {
+        return 42;
+    }
+
+    static publicStaticMethod() {
+        return ClassWithPrivateStaticMethod.#privateStaticMethod();
+    }
+}
+
+assert(ClassWithPrivateStaticMethod.publicStaticMethod() === 42);
+
+ +

私有实例方法

+ +

私有实例方法在类的实例中可用,它的访问方式的限制和私有实例字段相同。

+ +
class ClassWithPrivateMethod {
+  #privateMethod() {
+    return 'hello world';
+  }
+
+  getPrivateMessage() {
+      return #privateMethod();
+  }
+}
+
+const instance = new ClassWithPrivateMethod();
+console.log(instance.getPrivateMessage());
+// 预期输出值: "hello worl​d"
+ +

私有实例方法可以是生成器、异步或者异步生成器函数。私有gettersetter也是可能的:

+ +
class ClassWithPrivateAccessor {
+  #message;
+
+  get #decoratedMessage() {
+    return `✨${this.#message}✨`;
+  }
+  set #decoratedMessage(msg) {
+    this.#message = msg;
+  }
+
+  constructor() {
+    this.#decoratedMessage = 'hello world';
+    console.log(this.#decoratedMessage);
+  }
+}
+
+new ClassWithPrivateAccessor();
+// 预期输出值: "✨hello worl​d✨"
+
+ +

浏览器兼容性

+ +

公共类字段

+ + + +

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

+ +

私有类字段

+ + + +

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

+ +

另请参考:

+ + -- cgit v1.2.3-54-g00ecf