diff options
author | Florian Merz <me@fiji-flo.de> | 2021-02-11 12:56:40 +0100 |
---|---|---|
committer | Florian Merz <me@fiji-flo.de> | 2021-02-11 12:56:40 +0100 |
commit | 310fd066e91f454b990372ffa30e803cc8120975 (patch) | |
tree | d5d900deb656a5da18e0b60d00f0db73f3a2e88e /files/zh-cn/web/javascript/reference/classes/public_class_fields | |
parent | 8260a606c143e6b55a467edf017a56bdcd6cba7e (diff) | |
download | translated-content-310fd066e91f454b990372ffa30e803cc8120975.tar.gz translated-content-310fd066e91f454b990372ffa30e803cc8120975.tar.bz2 translated-content-310fd066e91f454b990372ffa30e803cc8120975.zip |
unslug zh-cn: move
Diffstat (limited to 'files/zh-cn/web/javascript/reference/classes/public_class_fields')
-rw-r--r-- | files/zh-cn/web/javascript/reference/classes/public_class_fields/index.html | 352 |
1 files changed, 352 insertions, 0 deletions
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 +--- +<div>{{JsSidebar("Classes")}}</div> + +<div class="note">公有(public)和私有(private)字段声明是一个JavaScript标准委员会<a href="https://tc39.github.io/beta/">TC39</a>提议的<a href="https://github.com/tc39/proposal-class-fields">试验性功能 (第3阶段)</a>。这项功能在浏览器中的支持还受限,但你可以通过<a href="https://babeljs.io/">Babel</a>等构建系统来使用它。参见下面的<a href="#Browser_compatibility">兼容性信息</a>。</div> + +<h2 id="公有字段">公有字段</h2> + +<p>静态公有字段和实例公有字段都是可编辑的,可遍历的,可配置的。它们本身不同于私有对应值(private counterparts)的是,它们参与原型的继承。</p> + +<h3 id="静态公有字段">静态公有字段</h3> + +<p>静态公有字段在你想要创建一个只在每个类里面只存在一份,而不会存在于你创建的每个类的实例中的属性时可以用到。你可以用它存放缓存数据、固定结构数据或者其他你不想在所有实例都复制一份的数据。</p> + +<p>静态公有字段是使用关键字 <code>static</code> 声明的。我们在声明一个类的时候,使用<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a>方法将静态公有字段添加到类的构造函数中。在类被声明之后,可以从类的构造函数访问静态公有字段。</p> + +<pre class="brush: js">class ClassWithStaticField { + static staticField = 'static field'; +} + +console.log(ClassWithStaticField.staticField); +// 预期输出值: "static field" +</pre> + +<p>没有设定初始化程序的字段将默认被初始化为<code>undefined</code>。</p> + +<pre class="brush: js">class ClassWithStaticField { + static staticField; +} + +console.assert(ClassWithStaticField.hasOwnProperty('staticField')); +console.log(ClassWithStaticField.staticField); +// 预期输出值: "undefined"</pre> + +<p>静态公有字段不会在子类里重复初始化,但我们可以通过原型链访问它们。</p> + +<pre class="brush: js">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"</pre> + +<p>当初始化字段时,<code>this</code>指向的是类的构造函数。你可以通过名字引用构造函数,并使用<code>super</code>获取到存在的超类构造函数。</p> + +<pre class="brush: js">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" +</pre> + +<h3 id="公有实例字段">公有实例字段</h3> + +<p>公有实例字段存在于类的每一个实例中。通过声明一个公有字段,我们可以确保该字段一直存在,而类的定义则会更加像是自我描述。</p> + +<p>公有实例字段可以在基类的构造过程中(构造函数主体运行前)使用<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a>添加,也可以在子类构造函数中的<code>super()</code>函数结束后添加。</p> + +<pre class="brush: js">class ClassWithInstanceField { + instanceField = 'instance field'; +} + +const instance = new ClassWithInstanceField(); +console.log(instance.instanceField); +// 预期输出值: "instance field"</pre> + +<p>没有设定初始化程序的字段将默认被初始化为<code>undefined</code>。</p> + +<pre class="brush: js">class ClassWithInstanceField { + instanceField; +} + +const instance = new ClassWithInstanceField(); +console.assert(instance.hasOwnProperty('instanceField')); +console.log(instance.instanceField); +// 预期输出值: "undefined"</pre> + +<p>和属性(properties)一样,字段名可以由计算得出。</p> + +<pre class="brush: js">const PREFIX = 'prefix'; + +class ClassWithComputedFieldName { + [`${PREFIX}Field`] = 'prefixed field'; +} + +const instance = new ClassWithComputedFieldName(); +console.log(instance.prefixField); +// 预期输出值: "prefixed field"</pre> + +<p>当初始化字段时,<code>this</code>指向的是类正在构造中的实例。和公共实例方法相同的是:你可以在子类中使用<code>super</code>来访问超类的原型。</p> + +<pre class="brush: js">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"</pre> + +<h2 id="公共方法">公共方法</h2> + +<h3 id="静态公共方法">静态公共方法</h3> + +<p>关键字<code><strong>static</strong></code>将为一个类定义一个静态方法。静态方法不会在实例中被调用,而只会被类本身调用。它们经常是工具函数,比如用来创建或者复制对象。</p> + +<p>{{EmbedInteractiveExample("pages/js/classes-static.html")}}</p> + +<div class="hidden"> +<p>这些交互案例的资源储存在GitHub仓库中。如果你想参与这个项目,请复制链接<a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a>并向我们发送拉取(pull)请求。</p> +</div> + +<p>静态方法是在类的赋值阶段用<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a>方法添加到类中的。静态方法是可编辑的、不可遍历的和可配置的。</p> + +<h3 id="公共实例方法">公共实例方法</h3> + +<p>正如其名,公共实例方法是可以在类的实例中使用的。</p> + +<pre class="brush: js">class ClassWithPublicInstanceMethod { + publicMethod() { + return 'hello world'; + } +} + +const instance = new ClassWithPublicInstanceMethod(); +console.log(instance.publicMethod()); +// 预期输出值: "hello world"</pre> + +<p>公共实例方法是在类的赋值阶段用<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a>方法添加到类中的。静态方法是可编辑的、不可遍历的和可配置的。</p> + +<p>你可以使用生成器(generator)、异步和异步生成器方法。</p> + +<pre class="brush: js">class ClassWithFancyMethods { + *generatorMethod() { } + async asyncMethod() { } + async *asyncGeneratorMethod() { } +}</pre> + +<p>在实例的方法中,<code>this</code>指向的是实例本身,你可以使用<code>super</code>访问到超类的原型,由此你可以调用超类的方法。</p> + +<pre class="brush: js">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 world" +</pre> + +<p><code>getter</code>和<code>setter</code>是和类的属性绑定的特殊方法,分别会在其绑定的属性被取值、赋值时调用。使用<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get">get</a>和<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set">set</a>句法定义实例的公共<code>getter</code>和<code>setter</code>。</p> + +<pre class="brush: js">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 world" + +instance.msg = 'cake'; +console.log(instance.msg); +// 预期输出值: "hello cake" +</pre> + +<h2 id="私有字段">私有字段</h2> + +<h3 id="静态私有字段">静态私有字段</h3> + +<p>静态私有字段可以在类声明本身内部的构造函数上被访问到。</p> + +<p>静态变量只能被静态方法访问的限制依然存在。</p> + +<pre class="brush: js">class ClassWithPrivateStaticField { + static #PRIVATE_STATIC_FIELD; + + static publicStaticMethod() { + ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42; + return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD; + } +} + +assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);</pre> + +<p>静态私有字段是在类赋值的时候被添加到类构造函数中的。</p> + +<p>静态私有字段有一个来源限制。只有定义静态私有字段的类可以访问该字段。这在使用<strong><code>this</code></strong>时,可能会导致不符合预期的行为。</p> + +<pre class="brush: js">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); +</pre> + +<h3 id="私有实例字段">私有实例字段</h3> + +<p>私有实例字段是通过<strong># names</strong>句型(读作“哈希名称”)声明的,即为识别符加一个前缀“#”。“#”是名称的一部分,也用于访问和声明。</p> + +<p>封装是语言强制实施的。引用不在作用域内的 # names 是语法错误。</p> + +<pre class="brush: js">class ClassWithPrivateField { + #privateField; + + constructor() { + this.#privateField = 42; + this.#randomField = 666; # Syntax error + } +} + +const instance = new ClassWithPrivateField(); +instance.#privateField === 42; // Syntax error +</pre> + +<h2 id="私有方法">私有方法</h2> + +<h3 id="静态私有方法">静态私有方法</h3> + +<p>和静态公共方法一样,静态私有方法也是在类里面而非实例中调用的。和静态私有字段一样,它们也只能在类的声明中访问。</p> + +<p>你可以使用生成器(generator)、异步和异步生成器方法。</p> + +<p>静态私有方法可以是生成器、异步或者异步生成器函数。</p> + +<pre class="brush: js">class ClassWithPrivateStaticMethod { + static #privateStaticMethod() { + return 42; + } + + static publicStaticMethod() { + return ClassWithPrivateStaticMethod.#privateStaticMethod(); + } +} + +assert(ClassWithPrivateStaticMethod.publicStaticMethod() === 42); +</pre> + +<h3 id="私有实例方法">私有实例方法</h3> + +<p>私有实例方法在类的实例中可用,它的访问方式的限制和私有实例字段相同。</p> + +<pre class="brush: js">class ClassWithPrivateMethod { + #privateMethod() { + return 'hello world'; + } + + getPrivateMessage() { + return #privateMethod(); + } +} + +const instance = new ClassWithPrivateMethod(); +console.log(instance.getPrivateMessage()); +// 预期输出值: "hello world"</pre> + +<p>私有实例方法可以是生成器、异步或者异步生成器函数。私有<code>getter</code>和<code>setter</code>也是可能的:</p> + +<pre class="brush: js">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 world✨" +</pre> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<h3 id="公共类字段">公共类字段</h3> + +<div class="hidden">此页面上的兼容性表是根据结构化数据生成的。 如果您想为数据做出贡献,请查看<a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>并向我们发送拉取请求。</div> + +<p>{{Compat("javascript.classes.public_class_fields")}}</p> + +<h3 id="私有类字段">私有类字段</h3> + +<div class="hidden">此页面上的兼容性表是根据结构化数据生成的。 如果您想为数据做出贡献,请查看<a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>并向我们发送拉取请求。</div> + +<p>{{Compat("javascript.classes.private_class_fields")}}</p> + +<h2 id="另请参考:">另请参考:</h2> + +<ul> + <li><a href="https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html">所有JS类元素的语义</a></li> +</ul> |