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
|
---
title: Приватные поля класса
slug: Web/JavaScript/Reference/Classes/Приватные_поля_класса
translation_of: Web/JavaScript/Reference/Classes/Private_class_fields
---
<div>{{JsSidebar("Classes")}}</div>
<p><span class="seoSummary">Свойства класса по умолчанию являются общедоступными и могут быть рассмотрены или изменены вне класса. Тем не менее, есть <a href="https://github.com/tc39/proposal-class-fields">экспериментальное предложение</a>, позволяющее определить приватные поля класса, используя префикс хэша <code>#</code>.</span></p>
<h2 id="Синтаксис">Синтаксис</h2>
<pre class="syntaxbox notranslate">class ClassWithPrivateField {
#privateField
}
class ClassWithPrivateMethod {
#privateMethod() {
return 'hello world'
}
}
class ClassWithPrivateStaticField {
static #PRIVATE_STATIC_FIELD
}
</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
}
}
console.assert(ClassWithPrivateStaticField.publicStaticMethod() === 42)</pre>
<p>Приватные статические поля добавляются в конструктор класса во время обработки класса.</p>
<p>Существует ограничение по происхождению частных статических полей. Только класс, который определяет приватное статическое поле, может получить доступ к этому полю.</p>
<p>Это может привести к неожиданному поведению при использовании this.</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 { }
let error = null
try {
SubClass.basePublicStaticMethod()
} catch(e) { error = e}
console.assert(error instanceof TypeError)
</pre>
<h3 id="Приватные_поля_экземпляров">Приватные поля экземпляров</h3>
<p>Приватные поля экзмепляров объявляются <strong>#имя </strong>(произносится как "хэш нэймс"), которые идентифицируются префиксом <code><strong>#</strong></code>. <code>#</code> является частью имени, а также используется для объявления и доступа.</p>
<p><span class="tlid-translation translation" lang="ru"><span title="">Инкапсуляция обеспечивается языком.</span> <span title="">Обращение к <code>#</code> именам вне области видимости является синтаксической ошибкой.</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>
<h3 id="Приватные_методы">Приватные методы</h3>
<h4 id="Приватные_статические_методы">Приватные статические методы</h4>
<p>Приватные статические методы</p>
<p>Как и их публичный эквивалент, приватные статические методы вызываются на самом классе, а не на экземплярах класса. Как и приватные статические поля, они доступны только изнутри объявления класса.</p>
<p>Приватные статические методы могут быть генераторами, асинхронными функциями и асинхронными функциями-генераторами.</p>
<pre class="brush: js notranslate">class ClassWithPrivateStaticMethod {
static #privateStaticMethod() {
return 42
}
static publicStaticMethod1() {
return ClassWithPrivateStaticMethod.#privateStaticMethod();
}
static publicStaticMethod2() {
return this.#privateStaticMethod();
}
}
console.assert(ClassWithPrivateStaticMethod.publicStaticMethod1() === 42);
console.assert(ClassWithPrivateStaticMethod.publicStaticMethod2() === 42);
</pre>
<p>Это может привести к неожиданному поведению при его использовании <strong><code>this</code></strong>. В следующем примере <code>this</code> относится к классу <code>Derived</code> (а не к классу <code>Base</code>), когда мы пытаемся вызвать <code>Derived.publicStaticMethod2()</code>, и, таким образом, имеет такое же "ограничение по происхождению", как упоминалось выше:</p>
<pre class="brush: js notranslate">class Base {
static #privateStaticMethod() {
return 42;
}
static publicStaticMethod1() {
return Base.#privateStaticMethod();
}
static publicStaticMethod2() {
return this.#privateStaticMethod();
}
}
class Derived extends Base {}
console.log(Derived.publicStaticMethod1()); // 42
console.log(Derived.publicStaticMethod2()); // TypeError
</pre>
<h4 id="Приватные_методы_экземпляровinstance">Приватные методы экземпляров(instance)</h4>
<p>Приватные методы экземпляров это методы, доступные у экземпляров класса, доступ к которым запрещен также, как у приватных полей класса.</p>
<pre class="brush: js notranslate">class ClassWithPrivateMethod {
#privateMethod() {
return 'hello world'
}
getPrivateMessage() {
return this.#privateMethod()
}
}
const instance = new ClassWithPrivateMethod()
console.log(instance.getPrivateMessage())
// expected output: "hello world"</pre>
<p>Приватные методы экземпляров могут быть генератором, async, или функциями async генератора. Приватные геттеры и сеттеры также возможны:</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 world✨"
</pre>
<h2 id="Спецификации">Спецификации</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Specification</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('Public and private instance fields', '#prod-FieldDefinition', 'FieldDefinition')}}</td>
</tr>
</tbody>
</table>
<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2>
<div class="hidden">Таблица совместимости на этой странице составлена из структурированных данных. Если Вы хотите внести свой вклад в данные, пожалуйста, посетите https://github.com/mdn/browser-compat-data и отправьте нам запрос.</div>
<p>{{Compat("javascript.classes.private_class_fields")}}</p>
<h2 id="См._также">См. также</h2>
<ul>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields">Public class fields</a></li>
<li><a href="https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html">The Semantics of All JS Class Elements</a></li>
</ul>
|