aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/classes/public_class_fields/index.html
blob: ea67222e500821d77f19f795575078e943facd3d (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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
---
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">Объявление публичных и приватных полей является <a href="https://github.com/tc39/proposal-class-fields">экспериментальной разработкой</a>, предложенной в коммитете стандартов JavaScript <a href="https://tc39.github.io/beta/">TC39</a>. Поддержка браузерами ограничена, но данное нововведение можно использовать посредством транспиляторов (например, <a href="https://babeljs.io/">Babel</a>). Смотрите информацию о совместимости ниже.</div>

<h2 id="Публичные_поля">Публичные поля</h2>

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

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

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

<p>Публичные статические поля объявляются при помощи ключевого слова <code>static</code>. Они добавляются в конструктор класса во время его создания с помощью <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a>. Доступ также осуществляется через конструктор класса.</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>Публичные поля экземпляра добавляются через <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty </a>либо перед тем, как будет исполнено тело конструктора в базовом классе, либо после того, как завершится <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>

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

<div class="hidden">
<p>The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p>
</div>

<p>Статические методы добавляются в конструктор класса с помощью <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a> во время его создания. Эти методы - изменяемые, неперечисляемые и настраиваемые свойства объекта.</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>Публичные методы добавляются в прототип класса во время его создания с помощью <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">Object.defineProperty</a>. Они изменяемы, неперечисляемы и настраиваемы.</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="Приватные_поля">Приватные поля</h2>

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

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

<p>Также сохраняется ограничение на вызов статических полей только внутри статических методов.</p>

<pre class="brush: js notranslate">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 notranslate">class BaseClassWithPrivateStaticField {
  static #PRIVATE_STATIC_FIELD;

  static basePublicStaticMethod() {
    this.#PRIVATE_STATIC_FIELD = 42;
    return this.#PRIVATE_STATIC_FIELD;
  }
}

class SubClass extends BaseClassWithPrivateStaticField { }

assertThrows(() =&gt; SubClass.basePublicStaticMethod(), TypeError);
</pre>

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

<p>Приватные поля объекта объявляются как <strong># names </strong>( произносятся как "hash names"), <span class="VIiyi" lang="ru"><span class="ChMk0b JLqJ4b"><span>которые являются идентификаторами с префиксом</span></span></span> #.  # <span class="VIiyi" lang="ru"><span class="ChMk0b JLqJ4b"><span>является частью самого имени и также используется для объявления и доступа</span></span></span>.</p>

<p><span class="VIiyi" lang="ru"><span class="ChMk0b JLqJ4b"><span>Инкапсуляция обеспечивается языком.</span></span> <span class="ChMk0b JLqJ4b"><span>Ссылка на # names вне области видимости является синтаксической ошибкой</span></span></span>.</p>

<pre class="brush: js notranslate">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><span class="VIiyi" lang="ru"><span class="ChMk0b JLqJ4b"><span>Как и публичные методы, приватные статические методы вызываются в классе, а не в экземплярах класса.</span></span> <span class="ChMk0b JLqJ4b"><span>Как и приватные статические поля, они доступны только из объявления класса.</span></span></span></p>

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

<pre class="brush: js notranslate">class ClassWithPrivateStaticMethod {
    static #privateStaticMethod() {
        return 42;
    }

    static publicStaticMethod() {
        return ClassWithPrivateStaticMethod.#privateStaticMethod();
    }
}

assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);
</pre>

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

<p>Приватные методы экземпляра объекта являются методами, доступными в экземплярах класса <span class="VIiyi" lang="ru"><span class="ChMk0b JLqJ4b"><span>чей доступ ограничен так же, как и</span></span></span> приватные поля экземпляра объекта.</p>

<pre class="brush: js notranslate">class ClassWithPrivateMethod {
  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
      return #privateMethod();
  }
}

const instance = new ClassWithPrivateMethod();
console.log(instance.getPrivateMessage());
// expected output: "hello worl​d"</pre>

<p>Приватные методы экземпляра объекта могут быть генераторами, асинхронными функциями и асинхронными генераторами. <span class="VIiyi" lang="ru"><span class="ChMk0b JLqJ4b"><span>Также возможны приватные геттеры и сеттеры</span></span></span>:</p>

<pre class="brush: js notranslate">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();
// expected output: "✨hello worl​d✨"
</pre>

<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2>

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



<p>{{Compat("javascript.classes.public_class_fields")}}</p>

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

<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</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>