aboutsummaryrefslogtreecommitdiff
path: root/files/ko/web/javascript/reference/classes/class_fields/index.html
blob: 959c65fadab51291d6c8cb20b1a03db8ad56f2a8 (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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
---
title: Class fields
slug: Web/JavaScript/Reference/Classes/Class_fields
translation_of: Web/JavaScript/Reference/Classes/Public_class_fields
---
<div>{{JsSidebar("Classes")}}</div>

<div class="note">
<p><strong>This page describes experimental features.</strong></p>

<p>Both Public and private field declarations are an <a href="https://github.com/tc39/proposal-class-fields">experimental feature (stage 3)</a> proposed at <a href="https://tc39.github.io/beta/">TC39</a>, the JavaScript standards committee.</p>

<p>Support in browsers is limited, but the feature can be used through a build step with systems like <a href="https://babeljs.io/">Babel</a>. See the <a href="#Browser_compatibility">compat information</a> below.</p>
</div>

<h2 id="Public_fields">Public fields</h2>

<p>static fields와 instance의 public fields 는 둘 다 writable, enumerable, configurable 한 프로퍼티들이다. 예를들면, 정 반대인 private 과는 다르게, unlike their private counterparts, static fields는 프로토타입 상속에 관여한다.</p>

<h3 id="Public_static_fields">Public static fields</h3>

<p>Public static fields 는 클래스에서 생성하는 모든 인스턴스에 대한 필드가 아닌, 클래스마다 단 한개의 필드가 존재하기를 원할 때 유용하게 사용할 수 있다. Public fields는 캐시, 고정된 설정값, 또는 인스턴스 간 복제할 필요가 없는 어떤 데이터 등에 유용하게 쓰일 수 있다.</p>

<p>Public static fields are declared using the <code>static</code> keyword. They are added to the class constructor at the time of class evaluation using {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}. They are accessed again from the class constructor.</p>

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

console.log(ClassWithStaticField.staticField)
// expected output: "static field"​
</pre>

<p>Fields without initializers are initialized to <code>undefined</code>.</p>

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

console.assert(ClassWithStaticField.hasOwnProperty('staticField'))
console.log(ClassWithStaticField.staticField)
// expected output: "undefined"</pre>

<p>Public static fields are not reinitialized on subclasses, but can be accessed via the prototype chain.</p>

<pre class="brush: js">class ClassWithStaticField {
  static baseStaticField = 'base field'
}

class SubClassWithStaticField extends ClassWithStaticField {
  static subStaticField = 'sub class field'
}

console.log(SubClassWithStaticField.subStaticField)
// expected output: "sub class field"

console.log(SubClassWithStaticField.baseStaticField)
// expected output: "base field"</pre>

<p>When initializing fields, <code>this</code> refers to the class constructor. You can also reference it by name, and use <code>super</code> to get the superclass constructor (if one exists).</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)
// expected output: "base static field"

console.log(SubClassWithStaticField.subStaticField)
// expected output: "base static method output"
</pre>

<h3 id="Public_instance_fields">Public instance fields</h3>

<p>Public instance fields exist on every created instance of a class. By declaring a public field, you can ensure the field is always present, and the class definition is more self-documenting.</p>

<p>Public instance fields are added with {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} either at construction time in the base class (before the constructor body runs), or just after <code>super()</code> returns in a subclass.</p>

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

const instance = new ClassWithInstanceField()
console.log(instance.instanceField)
// expected output: "instance field"</pre>

<p>Fields without initializers are initialized to <code>undefined</code>.</p>

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

const instance = new ClassWithInstanceField()
console.assert(instance.hasOwnProperty('instanceField'))
console.log(instance.instanceField)
// expected output: "undefined"</pre>

<p>Like properties, field names may be computed.</p>

<pre class="brush: js">const PREFIX = 'prefix'

class ClassWithComputedFieldName {
    [`${PREFIX}Field`] = 'prefixed field'
}

const instance = new ClassWithComputedFieldName()
console.log(instance.prefixField)
// expected output: "prefixed field"</pre>

<p>When initializing fields <code>this</code> refers to the class instance under construction. Just as in public instance methods, if you're in a subclass you can access the superclass prototype using <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)
// expected output: "base field"

console.log(sub.subInstanceField)
// expected output: "base method output"</pre>

<h2 id="Public_methods">Public methods</h2>

<h3 id="Public_static_methods">Public static methods</h3>

<p>The <code><strong>static</strong></code> keyword defines a static method for a class. Static methods aren't called on instances of the class. Instead, they're called on the class itself. These are often utility functions, such as functions to create or clone objects.</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>The static methods are added to the class constructor with {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} at class evaluation time. These methods are writable, non-enumerable, and configurable.</p>

<h3 id="Public_instance_methods">Public instance methods</h3>

<p>As the name implies, public instance methods are methods available on class instances.</p>

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

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

<p>Public instance methods are added to the class prototype at the time of class evaluation using {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}. They are writable, non-enumerable, and configurable.</p>

<p>You may make use of generator, async, and async generator functions.</p>

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

<p>Inside instance methods, <code>this</code> refers to the instance itself. In subclasses, <code>super</code> lets you access the superclass prototype, allowing you to call methods from the superclass.</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())
// expected output: "hello worl​d"
</pre>

<p>Getters and setters are special methods that bind to a class property and are called when that property is accessed or set. Use the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get">get</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set">set</a> syntax to declare a public instance getter or setter.</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 worl​d"

instance.msg = 'cake'
console.log(instance.msg)
// expected output: "hello cake"
</pre>

<h2 id="Private_fields">Private fields</h2>

<h3 id="Private_static_fields">Private static fields </h3>

<p>Private fields are accessible on the class constructor from inside the class declaration itself.</p>

<p>The limitation of static variables being called by only static methods still holds. </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>Private static fields are added to the class constructor at class evaluation time.</p>

<p>There is a provenance restriction on private static fields. Only the class which defines the private static field can access the field.</p>

<p>This can lead to unexpected behaviour when using <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(() =&gt; SubClass.basePublicStaticMethod(), TypeError)
</pre>

<h3 id="Private_instance_fields">Private instance fields</h3>

<p>Private instance fields are declared with <strong># names </strong>(pronounced "<em>hash names</em>"), which are identifiers prefixed with <code>#</code>. The <code>#</code> is a part of the name itself. It is used for declaration and accessing as well.</p>

<p>The encapsulation is enforced by the language. It is a syntax error to refer to <code>#</code> names from out of scope.</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="Private_Methods">Private Methods</h2>

<h3 id="Private_static_methods">Private static methods</h3>

<p>Like their public equivalent, private static methods are called on the class itself, not instances of the class. Like private static fields, they are only accessible from inside the class declaration.</p>

<p>Private static methods may be generator, async, and async generator functions.</p>

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

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

    static publicStaticMethod2() {
        return this.#privateStaticMethod();
    }
}

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

<p>This can lead to unexpected behaviour when using <strong><code>this</code></strong>(because <code>this</code> binding rule applies).</p>

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

<h3 id="Private_instance_methods">Private instance methods</h3>

<p>Private instance methods are methods available on class instances whose access is restricted in the same manner as private instance fields.</p>

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

  getPrivateMessage() {
      return this.#privateMethod()
  }
}

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

<p>Private instance methods may be generator, async, or async generator functions. Private getters and setters are also possible:</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();
// expected output: "✨hello worl​d✨"
</pre>

<h2 id="Specifications">Specifications</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
  <tr>
   <td><a href="https://tc39.es/proposal-class-fields/#prod-FieldDefinition">FieldDefinition production</a></td>
   <td>Stage 3</td>
   <td></td>
  </tr>
 </tbody>
</table>

<h2 id="Browser_compatibility">Browser compatibility</h2>

<h3 id="Public_class_fields">Public class fields</h3>



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

<h3 id="Private_class_fields">Private class fields</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="See_also">See also</h2>

<ul>
 <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>