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
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
|
---
title: クラス
slug: Web/JavaScript/Reference/Classes
tags:
- Classes
- Constructors
- ECMAScript 2015
- Guide
- Inheritance
- Intermediate
- JavaScript
translation_of: Web/JavaScript/Reference/Classes
---
<div>{{JsSidebar("Classes")}}</div>
<p>クラスはオブジェクトを作成するためのテンプレートです。それらは、そのデータを処理するためのコードでデータをカプセル化します。JS のクラスはプロトタイプに基づいて構築されていますが、ES5 のクラスライクなセマンティクスとは共有されない構文やセマンティクスも持っています。</p>
<h2 id="Defining_classes" name="Defining_classes">クラスの定義</h2>
<p>クラスは実際には「特別な{{jsxref("Functions", "関数", "", "true")}}」であり、{{jsxref("Operators/function", "関数式", "", "true")}}と{{jsxref("Statements/function", "関数宣言", "", "true")}}を定義することができるように、クラス構文にも{{jsxref("Operators/class", "クラス式", "", "true")}}と{{jsxref("Statements/class", "クラス宣言", "", "true")}}の 2 つの定義方法があります。</p>
<h3 id="Class_declarations" name="Class_declarations">クラス宣言</h3>
<p>クラスを定義するひとつの方法は、<strong>クラス宣言</strong>を使うことです。クラスを宣言するには、クラス名 (この例では "Rectangle") 付きで <code>class</code> キーワードを使います。</p>
<pre class="brush: js notranslate">class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}</pre>
<h4 id="Hoisting" name="Hoisting">ホイスティング(巻き上げ)</h4>
<p><strong>関数宣言</strong>と<strong>クラス宣言</strong>の重要な違いは、関数宣言では {{Glossary("Hoisting", "Hoisting")}} されるのに対し、クラス宣言ではされないことです。クラスにアクセスする前に、そのクラスを宣言する必要があります。そうしないと、{{jsxref("ReferenceError")}} が投げられます:</p>
<pre class="brush: js example-bad notranslate">const p = new Rectangle(); // ReferenceError
class Rectangle {}
</pre>
<h3 id="Class_expressions" name="Class_expressions">クラス式</h3>
<p>クラスを定義する別の方法は<strong>クラス式</strong>です。クラス式は、名前付きでも名前なしでもできます。名前付きクラスの名前は、クラス内のローカルとして扱われます。(ただし (インスタンスのではなく) クラスの {{jsxref("Function.name", "name")}} プロパティによって取得可能)</p>
<pre class="brush: js notranslate">// 名前なし
let Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// 出力: "Rectangle"
// 名前つき
let Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// 出力: "Rectangle2"
</pre>
<div class="note">
<p><strong>注:</strong> クラス<strong>式</strong>にも{{anch("Class declarations", "クラス宣言")}}で言及したのと同じホイスティング問題があります。</p>
</div>
<h2 id="Class_body_and_method_definitions" name="Class_body_and_method_definitions">クラス本体とメソッド定義</h2>
<p>中括弧 <code>{}</code> 内にクラス本体を記述します。クラス本体には、メソッドやコンストラクターといったクラスメンバを記述します。</p>
<h3 id="Strict_mode" name="Strict_mode">Strict モード</h3>
<p>クラス本体は <a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Strict_mode">Strict モード</a> で実行されます。つまり、ここで書かれたコードは、パフォーマンスを向上させるために、より厳密な構文に従います。そうでない場合はサイレントエラーが投げられます。なお、特定のキーワードは将来のバージョンの ECMAScript 用に予約されています。</p>
<h3 id="Constructor" name="Constructor">コンストラクター</h3>
<p>{{jsxref("Classes/constructor", "コンストラクター", "", "true")}}メソッドは、<code>class</code> で作成したオブジェクトを作成して初期化するための特別なメソッドです。"constructor" という名前の特別なメソッドは、クラスに 1 つしか定義できません。クラスに複数のコンストラクターメソッドが存在する場合、{{jsxref("SyntaxError")}} が投げられます。</p>
<p>スーパークラスのコンストラクターは <code>super</code> というキーワードで呼び出せます。</p>
<h3 id="Prototype_methods" name="Prototype_methods">プロトタイプメソッド</h3>
<p><a href="/ja/docs/Web/JavaScript/Reference/Functions/Method_definitions">メソッド定義</a>を参照してください。</p>
<pre class="brush: js notranslate">class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// ゲッター
get area() {
return this.calcArea();
}
// メソッド
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100</pre>
<h3 id="Static_methods_and_properties" name="Static_methods_and_properties">静的メソッドとプロパティ</h3>
<p>{{jsxref("Classes/static", "static", "", "true")}} キーワードは、クラスの静的メソッドまたはプロパティを定義します。静的メンバー(プロパティとメソッド)は、クラスを<a href="/ja/docs/Learn/JavaScript/Objects/Object-oriented_JS#Constructors_and_object_instances">インスタンス化</a>せずに呼び出され、クラスインスタンスを介して呼び出すことは<strong>できません</strong>。静的メソッドは、アプリケーションのユーティリティ関数を作成するためによく使用されますが、静的プロパティは、キャッシュ、固定構成、またはインスタンス間で複製する必要のないその他のデータに役立ちます。</p>
<pre class="brush: js notranslate">class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static displayName = "Point";
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
p2.displayName; // undefined
p2.distance; // undefined
console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
</pre>
<h3 id="Boxing_with_prototype_and_static_methods" name="Boxing_with_prototype_and_static_methods">プロトタイプと静的メソッドによるボクシング</h3>
<p><code>this</code> に値が付けられずに静的メソッドまたはプロトタイプメソッドが呼ばれると、<code>this</code> の値はメソッド内で <code>undefined</code> になります。たとえ <code>"use strict"</code> ディレクティブがなくても同じふるまいになります。なぜなら、<code>class</code> 本体の中のコードは常に Strict モードで実行されるからです。</p>
<pre class="brush: js notranslate">class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined
Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined</pre>
<p>上のコードを従来の関数ベースの構文を使って書くと、非 Strict モードでは、最初の <code>this</code> の値をもとにして、メソッド呼び出しの中で自動ボクシングが行われます。最初の値が <code>undefined</code> の場合、<code>this</code> にはグローバルオブジェクトが入ります。</p>
<p>Strict モードでは自動ボクシングは行われません。<code>this</code> の値はそのまま渡されます。</p>
<pre class="brush: js notranslate">function Animal() { }
Animal.prototype.speak = function() {
return this;
}
Animal.eat = function() {
return this;
}
let obj = new Animal();
let speak = obj.speak;
speak(); // グローバルオブジェクト(非厳格モード)
let eat = Animal.eat;
eat(); // グローバルオブジェクト(非厳格モード)
</pre>
<h3 id="Instance_properties" name="Instance_properties">インスタンスプロパティ</h3>
<p>インスタンスプロパティはクラスのメソッドの中で定義しなければなりません:</p>
<pre class="brush: js notranslate">class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}</pre>
<p>クラスに付随する静的なプロパティやプロトタイプのプロパティは、クラス本体の宣言の外で定義しなければなりません:</p>
<pre class="brush: js notranslate">Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;
</pre>
<h3 id="Field_declarations" name="Field_declarations">フィールド宣言</h3>
<div class="warning">
<p>パブリックフィールドとプライベートフィールドの宣言は 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> のようなシステムでのビルドステップを通して使用できます。</p>
</div>
<h4 id="Public_field_declarations" name="Public_field_declarations">パブリックフィールド宣言</h4>
<p>JavaScript のフィールド宣言構文を使って、上記の例は次のように書くことができます。</p>
<pre class="brush: js notranslate">class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
</pre>
<p>フィールドを事前宣言することで、クラス定義はより自己文書化され、フィールドは常に存在するようになります。</p>
<p>上記のように、フィールドはデフォルト値の有無にかかわらず宣言できます。</p>
<p>詳しい情報は、{{jsxref("Classes/Public_class_fields", "パブリッククラスフィールド", "", "true")}}を参照してください。</p>
<h4 id="Private_field_declarations" name="Private_field_declarations">プライベートフィールド宣言</h4>
<p>プライベートフィールドを使うと、宣言は下記のように洗練できます。</p>
<pre class="brush: js notranslate">class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
</pre>
<p>プライベートフィールドの参照はクラス本体内でのみ可能となり、クラス外からの参照はエラーとなります。クラス外からは見えないものを定義することで、クラスのユーザーが(変更される可能性のある)内部状態に依存できないようにします。</p>
<div class="note">
<p>プライベートフィールドは、事前宣言のみ可能です。</p>
</div>
<p>プライベートフィールドは通常のプロパティとは違い、<code>this</code> への追加によって後から作成することができません。</p>
<p>詳しい情報は、{{jsxref("Classes/Private_class_fields", "プライベートクラスフィールド", "", "true")}}を参照してください。</p>
<h2 id="Sub_classing_with_extends" name="Sub_classing_with_extends"><code>extends</code> によるサブクラス</h2>
<p><code><a href="/ja/docs/Web/JavaScript/Reference/Classes/extends">extends</a></code> キーワードは、クラスを別クラスの子として作成するために、<em>クラス宣言</em>または<em>クラス式</em>の中で使います。</p>
<pre class="brush: js notranslate">class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // スーパークラスのコンストラクターを呼び出し、name パラメータを渡す
}
speak() {
console.log(`${this.name} barks.`);
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
</pre>
<p>サブクラスにコンストラクターが存在する場合は、"this" を使う前に super() を呼ぶ必要があります。</p>
<p>従来の関数ベースの「クラス」も拡張できます:</p>
<pre class="brush: js notranslate">function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(`${this.name} makes a noise.`);
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
// 同様なメソッドでは、子のメソッドが親のメソッドよりも優先されます。</pre>
<p>クラスは通常の (生成不可能な) オブジェクトを拡張できないことに注意してください。通常のオブジェクトから継承したければ、代わりに {{jsxref("Object.setPrototypeOf()")}} を使います:</p>
<pre class="brush: js notranslate">const Animal = {
speak() {
console.log(`${this.name} makes a noise.`);
}
};
class Dog {
constructor(name) {
this.name = name;
}
}
// このコードが無いと、speak() を実行した時に TypeError になります。
Object.setPrototypeOf(Dog.prototype, Animal);
let d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.
</pre>
<h2 id="Species" name="Species">Species</h2>
<p>Array の派生クラスである <code>MyArray</code> の中で {{jsxref("Array")}} オブジェクトを返したいときもあるでしょう。species パターンは、デフォルトコンストラクタ-を上書きすることができます。</p>
<p>例えば、デフォルトコンストラクターを返す {{jsxref("Array.map", "map()")}} のようなメソッドを使っているとき、<code>MyArray</code> ではなく <code>Array</code> オブジェクトを返したいでしょう。{{jsxref("Symbol.species")}} シンボルを使うと次のように実現できます。</p>
<pre class="brush: js notranslate">class MyArray extends Array {
// species を親の Array コンストラクターで上書きする
static get [Symbol.species]() { return Array; }
}
let a = new MyArray(1,2,3);
let mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
</pre>
<h2 id="Super_class_calls_with_super" name="Super_class_calls_with_super"><code>super</code> でスーパークラスを呼び出す</h2>
<p><code><a href="/ja/docs/Web/JavaScript/Reference/Operators/super">super</a></code> キーワードを使ってスーパークラスのメソッドを呼び出せます。これはプロトタイプベースの継承よりも優れています。</p>
<pre class="brush: js notranslate">class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(`${this.name} roars.`);
}
}
let l = new Lion('Fuzzy');
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.
</pre>
<h2 id="Mix-ins" name="Mix-ins">ミックスイン</h2>
<p>抽象的なサブクラスや<em>ミックスイン</em>はクラスのためのテンプレートです。ECMAScript のクラスは 1 つだけスーパークラスを持つことができます。そのため、多重継承はできません。機能はスーパークラスから提供されます。</p>
<p>ECMAScript では、スーパークラスをインプットとして、そしてスーパークラスを継承した派生クラスをアウトプットとする関数を mix-in で実装できます:</p>
<pre class="brush: js notranslate">let calculatorMixin = Base => class extends Base {
calc() { }
};
let randomizerMixin = Base => class extends Base {
randomize() { }
};
</pre>
<p>ミックスインを使用したクラスを次のように記述することもできます:</p>
<pre class="brush: js notranslate">class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }</pre>
<h2 id="Specifications" name="Specifications">仕様</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">仕様書</th>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility" name="Browser_compatibility">ブラウザー実装状況</h2>
<p>{{Compat("javascript.classes")}}</p>
<h2 id="Re-running_a_class_definition" name="Re-running_a_class_definition">クラス定義の再実行</h2>
<p>クラスを再定義することはできません。再定義しようとすると <code>SyntaxError</code> が発生します。</p>
<p>Firefox のウェブコンソール(<strong>メニュー</strong> > <strong>ウェブ開発</strong> > <strong>ウェブコンソール</strong>)などでコードを試しているときに、同じ名前のクラス定義を 2 回実行すると、<code>SyntaxError: redeclaration of let <em>ClassName</em></code> が発生します。(この問題については {{Bug(1428672)}} でさらに詳しく説明しています。)Chrome Developer Tools で同様の操作を行うと、<code>Uncaught SyntaxError: Identifier '<em>ClassName</em>' has already been declared at <anonymous>:1:1</code> のようなメッセージが表示されます。</p>
<h2 id="See_also" name="See_also">関連情報</h2>
<ul>
<li>{{jsxref("Functions", "関数", "", "true")}}</li>
<li>{{jsxref("Statements/class", "クラス宣言", "", "true")}}</li>
<li>{{jsxref("Operators/class", "クラス式", "", "true")}}</li>
<li>{{jsxref("Classes/Public_class_fields", "パブリッククラスフィールド", "", "true")}}</li>
<li>{{jsxref("Classes/Private_class_fields", "プライベートクラスフィールド
", "", "true")}}</li>
<li>{{jsxref("Operators/super", "super")}}</li>
<li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-classes/">ブログ記事: "ES6 In Depth: Classes"</a></li>
<li><a href="https://github.com/tc39/proposal-class-fields">Fields and public/private class properties proposal (stage 3)</a></li>
</ul>
|