aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/classes/public_class_fields/index.html
blob: 865babfded4fa6eae84c89a896faec5fef2525f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
---
title: Публичные поля классов
slug: Web/JavaScript/Reference/Classes/Public_class_fields
tags:
  - Классы
  - JavaScript
  - Возможности языка
translation_of: Web/JavaScript/Reference/Classes/Public_class_fields
original_slug: Web/JavaScript/Reference/Classes/Class_fields
---
<div>{{JsSidebar("Classes")}}</div>

<div class="note">
  <p><strong>Примечание:</strong> Эта страница описывает экспериментальные возможности.</p>

  <p>Публичные и приватные поля — это <a
      href="https://github.com/tc39/proposal-class-fields">экспериментальная функция (stage
      3)</a>, предложенная комитетом по стандарту JavaScript <a href="https://tc39.es/">TC39</a>.</p>

  <p>Поддержка этой возможности в браузерах ограничена, но ее можно использовать посредством транспилирования с такими системами как <a href="https://babeljs.io/">Babel</a>. Смотрите <a href="#browser_compatibility">информацию о совместимости</a> ниже.</p>
</div>

<p>И статические, и публичные поля являются изменяемыми, перечисляемыми, настраиваемыми свойствами. Таким образом, в отличие от приватных полей, они участвуют в прототипном наследовании.</p>

<h2 id="Syntax">Синтаксис</h2>

<pre class="brush: js">class ClassWithInstanceField {
  instanceField = 'instance field'
}

class ClassWithStaticField {
  static staticField = 'static field'
}

class ClassWithPublicInstanceMethod {
  publicMethod() {
    return 'hello world'
  }
}
</pre>

<h2 id="Examples">Примеры</h2>

<h3 id="Публичные_статические_поля">Публичные статические поля</h3>

<p>Публичные статические поля полезны тогда, когда необходимо существование одного единственного поля для всего класса, а не для каждого созданного экземпляра по отдельности. Это полезно для кеша, конфигураций или любых прочих данных, которые одинаковы для всех экземпляров.</p>

<p>Публичные статические поля объявляются при помощи ключевого слова <code>static</code>. Они добавляются в конструктор класса во время его создания с помощью {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}. Доступ также осуществляется через конструктор класса.</p>

<pre class="brush: js notranslate">class ClassWithStaticField {
  static staticField = 'static field';
}

console.log(ClassWithStaticField.staticField);
// Ожидаемый вывод: "static field"
</pre>

<p>Поля без инициализации имеют значение <code>undefined</code>.</p>

<pre class="brush: js notranslate">class ClassWithStaticField {
  static staticField;
}

console.assert(ClassWithStaticField.hasOwnProperty('staticField'));
console.log(ClassWithStaticField.staticField);
// Ожидаемый вывод: "undefined"</pre>

<p>Публичные статические поля не переопределяются в наследниках класса, а могут быть доступны через иерархию прототипов.</p>

<pre class="brush: js notranslate">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 notranslate">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>Публичные поля экземпляра добавляются через {{jsxref("Global_Objects/Object/defineProperty",
  "Object.defineProperty()")}} либо перед тем, как будет исполнено тело конструктора в базовом классе, либо после того, как завершится <code>super()</code> в классе наследнике.</p>

<pre class="brush: js notranslate">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 notranslate">class ClassWithInstanceField {
  instanceField;
}

const instance = new ClassWithInstanceField();
console.assert(instance.hasOwnProperty('instanceField'));
console.log(instance.instanceField);
// Ожидаемый вывод: "undefined"</pre>

<p>Как и свойства, названия полей могут вычисляться.</p>

<pre class="brush: js notranslate">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 notranslate">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>

<pre class="brush: js notranslate">class ClassWithStaticMethod {
  static staticMethod() {
    return 'static method has been called.';
  }
}

console.log(ClassWithStaticMethod.staticMethod());
// expected output: "static method has been called."
</pre>

<p>Статические методы добавляются в конструктор класса с помощью {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} во время его создания. Эти методы - изменяемые, неперечисляемые и настраиваемые свойства объекта.</p>

<h3 id="Публичные_методы_экземпляра">Публичные методы экземпляра</h3>

<p>Как и следует из названия, публичные методы экземпляра это методы, доступные для вызова из экземпляров.</p>

<pre class="brush: js notranslate">class ClassWithPublicInstanceMethod {
  publicMethod() {
    return 'hello world';
  }
}

const instance = new ClassWithPublicInstanceMethod();
console.log(instance.publicMethod());
// Ожидаемый вывод: "hello worl​d"</pre>

<p>Публичные методы добавляются в прототип класса во время его создания с помощью {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}. Они изменяемы, неперечисляемы и настраиваемы.</p>

<p>Вы можете использовать генераторы, асинхронные функции и асинхронные генераторы.</p>

<pre class="brush: js notranslate">class ClassWithFancyMethods {
  *generatorMethod() { }
  async asyncMethod() { }
  async *asyncGeneratorMethod() { }
}</pre>

<p>Внутри методов экземпляра, <code>this</code> ссылается на сам экземпляр.<br>
 В классах наследниках, <code>super</code> даёт доступ к прототипу базового класса, позволяя вызывать его методы.</p>

<pre class="brush: js notranslate">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"
</pre>

<p>Геттеры и сеттеры это специальные методы, которые привязаны к свойствам класса и которые вызываются, когда к свойству обращаются или записывают. Используйте <a href="/ru/docs/Web/JavaScript/Reference/Functions/get">get</a> и <a href="/ru/docs/Web/JavaScript/Reference/Functions/set">set</a> для объявления публичных геттеров и сеттеров экземпляра.</p>

<pre class="brush: js notranslate">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);
// Ожидаемый вывод: "hello worl​d"

instance.msg = 'cake';
console.log(instance.msg);
// Ожидаемый вывод: "hello cake"
</pre>

<h2 id="Specifications">Спецификации</h2>

{{Specifications}}

<h2 id="Browser_compatibility">Браузерная совместимость</h2>

<p>{{Compat}}</p>

<h2 id="See_also">Смотрите также</h2>

<ul>
  <li><a href="https://v8.dev/features/class-fields">Публичные и приватные поля классов</a> статья на сайте v8.dev.</li>
  <li><a href="https://github.com/tc39/proposal-class-fields#class-field-declarations-for-javascript">Объявление полей класса в JavaScript</a>, от авторов <a href="https://github.com/tc39/proposal-class-fields">Публичных и приватных полей экземпляра</a></li>
  <li><a href="https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html">Семантика всех элементов JS класса</a></li>
</ul>