From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- .../reference/classes/constructor/index.html | 190 +++++++++ .../reference/classes/extends/index.html | 91 +++++ .../ja/web/javascript/reference/classes/index.html | 424 +++++++++++++++++++++ .../classes/private_class_fields/index.html | 207 ++++++++++ .../classes/public_class_fields/index.html | 267 +++++++++++++ .../javascript/reference/classes/static/index.html | 132 +++++++ 6 files changed, 1311 insertions(+) create mode 100644 files/ja/web/javascript/reference/classes/constructor/index.html create mode 100644 files/ja/web/javascript/reference/classes/extends/index.html create mode 100644 files/ja/web/javascript/reference/classes/index.html create mode 100644 files/ja/web/javascript/reference/classes/private_class_fields/index.html create mode 100644 files/ja/web/javascript/reference/classes/public_class_fields/index.html create mode 100644 files/ja/web/javascript/reference/classes/static/index.html (limited to 'files/ja/web/javascript/reference/classes') diff --git a/files/ja/web/javascript/reference/classes/constructor/index.html b/files/ja/web/javascript/reference/classes/constructor/index.html new file mode 100644 index 0000000000..e6fd5e6ddb --- /dev/null +++ b/files/ja/web/javascript/reference/classes/constructor/index.html @@ -0,0 +1,190 @@ +--- +title: コンストラクター +slug: Web/JavaScript/Reference/Classes/constructor +tags: + - Classes + - ECMAScript 2015 + - JavaScript + - Language feature +translation_of: Web/JavaScript/Reference/Classes/constructor +--- +
{{jsSidebar("Classes")}}
+ +

constructor メソッドは、 {{jsxref("Statements/class", "class")}} で作成されたオブジェクトの生成と初期化のための特殊なメソッドです。

+ +
{{EmbedInteractiveExample("pages/js/classes-constructor.html")}}
+ + + +

構文

+ +
constructor([arguments]) { ... }
+ +

解説

+ +

コンストラクターを使用すると、インスタンス化されたオブジェクトに対して、他のメソッドを呼び出す前に行う必要のある独自の初期化を提供することができます。

+ +
class Person {
+
+  constructor(name) {
+    this.name = name;
+  }
+
+  introduce() {
+    console.log(`Hello, my name is ${this.name}`);
+  }
+
+}
+
+const otto = new Person('Otto');
+
+otto.introduce();
+ +

独自のコンストラクターを提供しなかった場合は、既定のコンストラクターが提供されます。クラスが基底クラスである場合、既定のコンストラクターは空です。

+ +
constructor() {}
+ +

クラスが派生クラスの場合、既定のコンストラクターが親コンストラクターを呼び出し、与えられた引数を渡します。

+ +
constructor(...args) {
+  super(...args);
+}
+ +

それがこのようなコードを動作させることができます。

+ +
class ValidationError extends Error {
+
+  printCustomerMessage() {
+    return `Validation failed :-( (details: ${this.message})`;
+  }
+
+}
+
+try {
+  throw new ValidationError("Not a valid phone number");
+} catch (error) {
+   if (error instanceof ValidationError) {
+    console.log(error.name); // This is Error instead of ValidationError!
+    console.log(error.printCustomerMessage());
+  } else {
+    console.log('Unknown error', error);
+    throw error;
+  }
+}
+ +

ValidationError クラスは、独自の初期化を行う必要がないため、明示的なコンストラクターは必要ありません。既定のコンストラクターは、与えられた引数から親の Error の初期化を行います。

+ +

ただし、独自のコンストラクターを提供し、クラスが親クラスから派生している場合は、 super を使用して親クラスのコンストラクターを明示的に呼び出す必要があります。例えば、以下のようになります。

+ +
class ValidationError extends Error {
+
+  constructor(message) {
+    super(message);  // call parent class constructor
+    this.name = 'ValidationError';
+    this.code = '42';
+  }
+
+  printCustomerMessage() {
+     return `Validation failed :-( (details: ${this.message}, code: ${this.code})`;
+  }
+
+}
+
+try {
+  throw new ValidationError("Not a valid phone number");
+} catch (error) {
+   if (error instanceof ValidationError) {
+    console.log(error.name); // Now this is ValidationError!
+    console.log(error.printCustomerMessage());
+  } else {
+    console.log('Unknown error', error);
+    throw error;
+  }
+}
+
+
+ +

クラスには "constructor" という名前の特別なメソッドが 1 つだけ存在します。クラス内に複数の constructor メソッドが存在すると、 {{jsxref("SyntaxError")}} エラーが発生します。

+ +

+ +

constructor メソッドの使用

+ +

このコードスニペットは、classes sample (ライブデモ) から転載しています。

+ +
class Square extends Polygon {
+  constructor(length) {
+    // Here, it calls the parent class' constructor with lengths
+    // provided for the Polygon's width and height
+    super(length, length);
+    // NOTE: In derived classes, `super()` must be called before you
+    // can use `this`. Leaving this out will cause a ReferenceError.
+    this.name = 'Square';
+  }
+
+  get area() {
+    return this.height * this.width;
+  }
+
+  set area(value) {
+    this.height = value**0.5;
+    this.width = value**0.5;
+  }
+}
+ +

他の例

+ +

ここでは、 Square クラスのプロトタイプが変更されていますが、新しいインスタンスが作成されたときには、その基底クラスである Polygon のコンストラクターが呼び出されます。

+ +
class Polygon {
+    constructor() {
+        this.name = "Polygon";
+    }
+}
+
+class Square extends Polygon {
+    constructor() {
+        super();
+    }
+}
+
+class Rectangle {}
+
+Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
+
+console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
+console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true
+
+let newInstance = new Square();
+console.log(newInstance.name); //Polygon
+ +

仕様書

+ + + + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-static-semantics-constructormethod', 'Constructor Method')}}
+ +

ブラウザーの互換性

+ + + +

{{Compat("javascript.classes.constructor")}}

+ +

関連情報

+ + diff --git a/files/ja/web/javascript/reference/classes/extends/index.html b/files/ja/web/javascript/reference/classes/extends/index.html new file mode 100644 index 0000000000..e4c31b4128 --- /dev/null +++ b/files/ja/web/javascript/reference/classes/extends/index.html @@ -0,0 +1,91 @@ +--- +title: extends +slug: Web/JavaScript/Reference/Classes/extends +tags: + - Classes + - ECMAScript 2015 + - JavaScript + - Language feature +translation_of: Web/JavaScript/Reference/Classes/extends +--- +
{{jsSidebar("Classes")}}
+ +

extends キーワードはクラス宣言クラス式の中で、他のクラスの子であるクラスを生成するために使用します。

+ +
{{EmbedInteractiveExample("pages/js/classes-extends.html")}}
+ + + +

構文

+ +
class ChildClass extends ParentClass { ... }
+ +

解説

+ +

extends キーワードは、独自のクラスや組込みオブジェクトをサブクラス化するために使用することができます。

+ +

拡張したものの .prototype は、{{jsxref("Object")}} か {{jsxref("null")}} である必要があります。

+ +

+ +

extends の使用

+ +

最初の例では、 Square と呼ばれるクラスを Polygon と呼ばれるクラスから作成します。この例は、ライブデモ (ソース) から転載しています。

+ +
class Square extends Polygon {
+  constructor(length) {
+    // ここでは、親クラスのコンストラクターを呼び出し、
+    // Polygon の幅と高さの寸法を渡します。
+    super(length, length);
+    // 注: 派生クラスでは、 'this' を使う前に super() を
+    // 呼び出さなくてはなりません。さもないと参照エラーになります。
+    this.name = 'Square';
+  }
+
+  get area() {
+    return this.height * this.width;
+  }
+}
+ +

組込みオブジェクトでの extends の使用

+ +

この例では、組込みの {{jsxref("Date")}} オブジェクトを拡張します。この例は、ライブデモ (ソース) から転載しています。

+ +
class myDate extends Date {
+
+  getFormattedDate() {
+    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+    return this.getDate() + '-' + months[this.getMonth()] + '-' + this.getFullYear();
+  }
+}
+
+ +

仕様書

+ + + + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-class-definitions', 'extends')}}
+ +

ブラウザーの互換性

+ + + +

{{Compat("javascript.classes.extends")}}

+ +

関連情報

+ + diff --git a/files/ja/web/javascript/reference/classes/index.html b/files/ja/web/javascript/reference/classes/index.html new file mode 100644 index 0000000000..3f711b47ed --- /dev/null +++ b/files/ja/web/javascript/reference/classes/index.html @@ -0,0 +1,424 @@ +--- +title: クラス +slug: Web/JavaScript/Reference/Classes +tags: + - Classes + - Constructors + - ECMAScript 2015 + - Guide + - Inheritance + - Intermediate + - JavaScript +translation_of: Web/JavaScript/Reference/Classes +--- +
{{JsSidebar("Classes")}}
+ +

クラスはオブジェクトを作成するためのテンプレートです。それらは、そのデータを処理するためのコードでデータをカプセル化します。JS のクラスはプロトタイプに基づいて構築されていますが、ES5 のクラスライクなセマンティクスとは共有されない構文やセマンティクスも持っています。

+ +

クラスの定義

+ +

クラスは実際には「特別な{{jsxref("Functions", "関数", "", "true")}}」であり、{{jsxref("Operators/function", "関数式", "", "true")}}と{{jsxref("Statements/function", "関数宣言", "", "true")}}を定義することができるように、クラス構文にも{{jsxref("Operators/class", "クラス式", "", "true")}}と{{jsxref("Statements/class", "クラス宣言", "", "true")}}の 2 つの定義方法があります。

+ +

クラス宣言

+ +

クラスを定義するひとつの方法は、クラス宣言を使うことです。クラスを宣言するには、クラス名 (この例では "Rectangle") 付きで class キーワードを使います。

+ +
class Rectangle {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+}
+ +

ホイスティング(巻き上げ)

+ +

関数宣言クラス宣言の重要な違いは、関数宣言では {{Glossary("Hoisting", "Hoisting")}} されるのに対し、クラス宣言ではされないことです。クラスにアクセスする前に、そのクラスを宣言する必要があります。そうしないと、{{jsxref("ReferenceError")}} が投げられます:

+ +
const p = new Rectangle(); // ReferenceError
+
+class Rectangle {}
+
+ +

クラス式

+ +

クラスを定義する別の方法はクラス式です。クラス式は、名前付きでも名前なしでもできます。名前付きクラスの名前は、クラス内のローカルとして扱われます。(ただし (インスタンスのではなく) クラスの {{jsxref("Function.name", "name")}} プロパティによって取得可能)

+ +
// 名前なし
+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"
+
+ +
+

注: クラスにも{{anch("Class declarations", "クラス宣言")}}で言及したのと同じホイスティング問題があります。

+
+ +

クラス本体とメソッド定義

+ +

中括弧 {} 内にクラス本体を記述します。クラス本体には、メソッドやコンストラクターといったクラスメンバを記述します。

+ +

Strict モード

+ +

クラス本体は Strict モード で実行されます。つまり、ここで書かれたコードは、パフォーマンスを向上させるために、より厳密な構文に従います。そうでない場合はサイレントエラーが投げられます。なお、特定のキーワードは将来のバージョンの ECMAScript 用に予約されています。

+ +

コンストラクター

+ +

{{jsxref("Classes/constructor", "コンストラクター", "", "true")}}メソッドは、class で作成したオブジェクトを作成して初期化するための特別なメソッドです。"constructor" という名前の特別なメソッドは、クラスに 1 つしか定義できません。クラスに複数のコンストラクターメソッドが存在する場合、{{jsxref("SyntaxError")}} が投げられます。

+ +

スーパークラスのコンストラクターは super というキーワードで呼び出せます。

+ +

プロトタイプメソッド

+ +

メソッド定義を参照してください。

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

静的メソッドとプロパティ

+ +

{{jsxref("Classes/static", "static", "", "true")}} キーワードは、クラスの静的メソッドまたはプロパティを定義します。静的メンバー(プロパティとメソッド)は、クラスをインスタンス化せずに呼び出され、クラスインスタンスを介して呼び出すことはできません。静的メソッドは、アプリケーションのユーティリティ関数を作成するためによく使用されますが、静的プロパティは、キャッシュ、固定構成、またはインスタンス間で複製する必要のないその他のデータに役立ちます。

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

プロトタイプと静的メソッドによるボクシング

+ +

this に値が付けられずに静的メソッドまたはプロトタイプメソッドが呼ばれると、this の値はメソッド内で undefined になります。たとえ "use strict" ディレクティブがなくても同じふるまいになります。なぜなら、class 本体の中のコードは常に Strict モードで実行されるからです。

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

上のコードを従来の関数ベースの構文を使って書くと、非 Strict モードでは、最初の this の値をもとにして、メソッド呼び出しの中で自動ボクシングが行われます。最初の値が undefined の場合、this にはグローバルオブジェクトが入ります。

+ +

Strict モードでは自動ボクシングは行われません。this の値はそのまま渡されます。

+ +
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(); // グローバルオブジェクト(非厳格モード)
+
+ +

インスタンスプロパティ

+ +

インスタンスプロパティはクラスのメソッドの中で定義しなければなりません:

+ +
class Rectangle {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+}
+ +

クラスに付随する静的なプロパティやプロトタイプのプロパティは、クラス本体の宣言の外で定義しなければなりません:

+ +
Rectangle.staticWidth = 20;
+Rectangle.prototype.prototypeWidth = 25;
+
+ +

フィールド宣言

+ +
+

パブリックフィールドとプライベートフィールドの宣言は JavaScript 標準委員会の TC39 で提案されている実験的機能(ステージ 3)です。ブラウザーでのサポートは限られていますが、この機能は Babel のようなシステムでのビルドステップを通して使用できます。

+
+ +

パブリックフィールド宣言

+ +

JavaScript のフィールド宣言構文を使って、上記の例は次のように書くことができます。

+ +
class Rectangle {
+  height = 0;
+  width;
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+}
+
+ +

フィールドを事前宣言することで、クラス定義はより自己文書化され、フィールドは常に存在するようになります。

+ +

上記のように、フィールドはデフォルト値の有無にかかわらず宣言できます。

+ +

詳しい情報は、{{jsxref("Classes/Public_class_fields", "パブリッククラスフィールド", "", "true")}}を参照してください。

+ +

プライベートフィールド宣言

+ +

プライベートフィールドを使うと、宣言は下記のように洗練できます。

+ +
class Rectangle {
+  #height = 0;
+  #width;
+  constructor(height, width) {
+    this.#height = height;
+    this.#width = width;
+  }
+}
+
+ +

プライベートフィールドの参照はクラス本体内でのみ可能となり、クラス外からの参照はエラーとなります。クラス外からは見えないものを定義することで、クラスのユーザーが(変更される可能性のある)内部状態に依存できないようにします。

+ +
+

プライベートフィールドは、事前宣言のみ可能です。

+
+ +

プライベートフィールドは通常のプロパティとは違い、this への追加によって後から作成することができません。

+ +

詳しい情報は、{{jsxref("Classes/Private_class_fields", "プライベートクラスフィールド", "", "true")}}を参照してください。

+ +

extends によるサブクラス

+ +

extends キーワードは、クラスを別クラスの子として作成するために、クラス宣言またはクラス式の中で使います。

+ +
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.
+
+ +

サブクラスにコンストラクターが存在する場合は、"this" を使う前に super() を呼ぶ必要があります。

+ +

従来の関数ベースの「クラス」も拡張できます:

+ +
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.
+
+// 同様なメソッドでは、子のメソッドが親のメソッドよりも優先されます。
+ +

クラスは通常の (生成不可能な) オブジェクトを拡張できないことに注意してください。通常のオブジェクトから継承したければ、代わりに {{jsxref("Object.setPrototypeOf()")}} を使います:

+ +
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.
+
+ +

Species

+ +

Array の派生クラスである MyArray の中で {{jsxref("Array")}} オブジェクトを返したいときもあるでしょう。species パターンは、デフォルトコンストラクタ-を上書きすることができます。

+ +

例えば、デフォルトコンストラクターを返す {{jsxref("Array.map", "map()")}} のようなメソッドを使っているとき、MyArray ではなく Array オブジェクトを返したいでしょう。{{jsxref("Symbol.species")}} シンボルを使うと次のように実現できます。

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

super でスーパークラスを呼び出す

+ +

super キーワードを使ってスーパークラスのメソッドを呼び出せます。これはプロトタイプベースの継承よりも優れています。

+ +
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.
+
+ +

ミックスイン

+ +

抽象的なサブクラスやミックスインはクラスのためのテンプレートです。ECMAScript のクラスは 1 つだけスーパークラスを持つことができます。そのため、多重継承はできません。機能はスーパークラスから提供されます。

+ +

ECMAScript では、スーパークラスをインプットとして、そしてスーパークラスを継承した派生クラスをアウトプットとする関数を mix-in で実装できます:

+ +
let calculatorMixin = Base => class extends Base {
+  calc() { }
+};
+
+let randomizerMixin = Base => class extends Base {
+  randomize() { }
+};
+
+ +

ミックスインを使用したクラスを次のように記述することもできます:

+ +
class Foo { }
+class Bar extends calculatorMixin(randomizerMixin(Foo)) { }
+ + +

仕様

+ + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}
+ +

ブラウザー実装状況

+ + + +

{{Compat("javascript.classes")}}

+ +

クラス定義の再実行

+ +

クラスを再定義することはできません。再定義しようとすると SyntaxError が発生します。

+ +

Firefox のウェブコンソール(メニュー > ウェブ開発 > ウェブコンソール)などでコードを試しているときに、同じ名前のクラス定義を 2 回実行すると、SyntaxError: redeclaration of let ClassName が発生します。(この問題については {{Bug(1428672)}} でさらに詳しく説明しています。)Chrome Developer Tools で同様の操作を行うと、Uncaught SyntaxError: Identifier 'ClassName' has already been declared at <anonymous>:1:1 のようなメッセージが表示されます。

+ +

関連情報

+ + diff --git a/files/ja/web/javascript/reference/classes/private_class_fields/index.html b/files/ja/web/javascript/reference/classes/private_class_fields/index.html new file mode 100644 index 0000000000..6310aa5092 --- /dev/null +++ b/files/ja/web/javascript/reference/classes/private_class_fields/index.html @@ -0,0 +1,207 @@ +--- +title: プライベートクラスフィールド +slug: Web/JavaScript/Reference/Classes/Private_class_fields +tags: + - Classes + - JavaScript + - Language feature +translation_of: Web/JavaScript/Reference/Classes/Private_class_fields +--- +
{{JsSidebar("Classes")}}
+ +

クラスのプロパティはデフォルトで公開されており、クラスの外で調べたり変更したりすることができます。しかし、ハッシュ # 接頭辞を使ってプライベートなクラスフィールドを定義できるようにする実験的な提案があります。

+ +

構文

+ +
class ClassWithPrivateField {
+  #privateField
+}
+
+class ClassWithPrivateMethod {
+  #privateMethod() {
+    return 'hello world'
+  }
+}
+
+class ClassWithPrivateStaticField {
+  static #PRIVATE_STATIC_FIELD
+}
+
+ +

+ +

プライベートスタティックフィールド

+ +

プライベートフィールドは、クラスのコンストラクタ上でクラス宣言の内部からアクセスできます。

+ +

静的変数は静的メソッドからのみ呼び出せるという制限はまだあります。

+ +
class ClassWithPrivateStaticField {
+  static #PRIVATE_STATIC_FIELD
+
+  static publicStaticMethod() {
+    ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42
+    return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD
+  }
+}
+
+console.assert(ClassWithPrivateStaticField.publicStaticMethod() === 42)
+ +

プライベートスタティックフィールドは、クラスの評価時にクラスのコンストラクタに追加されます。

+ +

プライベートスタティックフィールドには、プライベートスタティックフィールドを定義しているクラスのみが、そのフィールドにアクセスできるという出自制限があります。

+ +

これは、this を使用しているときに予期しない動作をする可能性があります。

+ +
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)
+
+ +

プライベートインスタンスフィールド

+ +

プライベートインスタンスフィールドは # names (ハッシュネーム) で宣言され、これは # を先頭にした識別子です。この # は名前の一部で、宣言やアクセスにも使われます。

+ +

このカプセル化は言語によって強制されています。範囲外から # の名前を参照するのは構文エラーです。

+ +
class ClassWithPrivateField {
+  #privateField
+
+  constructor() {
+    this.#privateField = 42
+    this.#randomField = 444 // Syntax error
+  }
+}
+
+const instance = new ClassWithPrivateField()
+instance.#privateField === 42 // Syntax error
+
+ +

プライベートメソッド

+ +

プライベートスタティックメソッド

+ +

プライベートスタティックメソッドは、パブリックと同様に、クラスのインスタンスではなく、クラス自体から呼び出されます。プライベートスタティックフィールドと同様に、クラス宣言の内部からのみアクセス可能です。

+ +

プライベートスタティックメソッドは、ジェネレーター関数、async、非同期ジェネレーター関数、などがあります

+ +
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);
+
+ +

this を使用すると、予期しない動作が発生する可能性があります。次の例では、Derived.publicStaticMethod2() を呼び出そうとしたときに、this派生 クラス(Base クラスではない)を参照しており、上で述べたのと同じ "出自制限" を示します。

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

プライベートインスタンスメソッド

+ +

プライベートインスタンスメソッドは、プライベートインスタンスフィールドと同様にアクセスが制限されているクラスインスタンスで利用できるメソッドです。

+ +
class ClassWithPrivateMethod {
+  #privateMethod() {
+    return 'hello world'
+  }
+
+  getPrivateMessage() {
+    return this.#privateMethod()
+  }
+}
+
+const instance = new ClassWithPrivateMethod()
+console.log(instance.getPrivateMessage())
+// expected output: "hello worl​d"
+ +

プライベートインスタンスメソッドは、ジェネレーター関数、async、非同期ジェネレーター関数のいずれかになります。プライベートなゲッターやセッターも可能です。

+ +
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✨"
+
+ +

仕様

+ + + + + + + + + + + + +
仕様書
{{SpecName('Public and private instance fields', '#prod-FieldDefinition', 'FieldDefinition')}}
+ +

ブラウザー実装状況

+ + + +

{{Compat("javascript.classes.private_class_fields")}}

+ +

関連情報

+ + diff --git a/files/ja/web/javascript/reference/classes/public_class_fields/index.html b/files/ja/web/javascript/reference/classes/public_class_fields/index.html new file mode 100644 index 0000000000..18614027ce --- /dev/null +++ b/files/ja/web/javascript/reference/classes/public_class_fields/index.html @@ -0,0 +1,267 @@ +--- +title: パブリッククラスフィールド +slug: Web/JavaScript/Reference/Classes/Public_class_fields +tags: + - Classes + - JavaScript + - Language feature +translation_of: Web/JavaScript/Reference/Classes/Public_class_fields +--- +
{{JsSidebar("Classes")}}
+ +
+

このページは、実験的な機能について説明しています。

+ +

パブリックフィールド宣言とプライベートフィールド宣言の両方は、JavaScript の標準化委員会である TC39 で提案された実験的な機能(ステージ 3)です。

+ +

ブラウザーのサポートは限られていますが、Babel のようなシステムではビルドステップを経て機能を利用することができます。下記の互換性情報を参照してください。

+
+ +

パブリックスタティックフィールドとパブリックインスタンスフィールドは、書き込み可能、列挙可能、設定可能なプロパティです。そのため、プライベートとは異なり、プロトタイプの継承に参加します。

+ +

構文

+ +
class ClassWithInstanceField {
+  instanceField = 'instance field'
+}
+
+class ClassWithStaticField {
+  static staticField = 'static field'
+}
+
+class ClassWithPublicInstanceMethod {
+  publicMethod() {
+    return 'hello world'
+  }
+}
+
+ +

+ +

パブリックスタティックフィールド

+ +

パブリックスタティックフィールドは、すべてのクラスインスタンスを作成するのではなく、クラスごとに一度だけフィールドが存在するようにしたい場合に役立ちます。これは、キャッシュや固定設定、その他インスタンス間で複製する必要のないデータなどに便利です。

+ +

パブリックスタティックフィールドは、static キーワードを使用して宣言されます。これらは、クラスの評価時に{{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} を使用してコンストラクタに追加され、その後はコンストラクタからアクセスします。

+ +
class ClassWithStaticField {
+  static staticField = 'static field'
+}
+
+console.log(ClassWithStaticField.staticField)
+// expected output: "static field"​
+
+ +

初期化子のないフィールドは undefined に初期化されます。

+ +
class ClassWithStaticField {
+  static staticField
+}
+
+console.assert(ClassWithStaticField.hasOwnProperty('staticField'))
+console.log(ClassWithStaticField.staticField)
+// expected output: "undefined"
+ +

パブリックスタティックフィールドはサブクラスを再初期化しませんが、プロトタイプチェーンを介してアクセスすることができます。

+ +
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"
+ +

フィールドを初期化する場合、this はクラスのコンストラクタを参照します。また、名前で参照し、スーパークラスのコンストラクタが存在する場合は super を使用してスーパークラスのコンストラクタを取得することもできます (存在する場合)。

+ +
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"
+
+ +

パブリックインスタンスフィールド

+ +

パブリックインスタンスフィールドは、作成されたクラスのすべてのインスタンスに存在します。パブリックフィールドを宣言することで、フィールドが常に存在していることを確認でき、クラスの定義がより自己文書化されます。

+ +

パブリック インスタンスフィールドは、ベースクラスの構築時(コンストラクタ本体が実行される前)、またはサブクラスの super() が返された直後のいずれかに {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} で追加されます。

+ +
class ClassWithInstanceField {
+  instanceField = 'instance field'
+}
+
+const instance = new ClassWithInstanceField()
+console.log(instance.instanceField)
+// expected output: "instance field"
+ +

初期化子のないフィールドは undefined に初期化されます。

+ +
class ClassWithInstanceField {
+  instanceField
+}
+
+const instance = new ClassWithInstanceField()
+console.assert(instance.hasOwnProperty('instanceField'))
+console.log(instance.instanceField)
+// expected output: "undefined"
+ +

プロパティと同様に、フィールド名を計算することができます。

+ +
const PREFIX = 'prefix'
+
+class ClassWithComputedFieldName {
+    [`${PREFIX}Field`] = 'prefixed field'
+}
+
+const instance = new ClassWithComputedFieldName()
+console.log(instance.prefixField)
+// expected output: "prefixed field"
+ +

フィールドを初期化する場合、this は構築中のクラスインスタンスを参照します。パブリックインスタンスメソッドと同じように、サブクラスにいる場合は super を使って superclass プロトタイプにアクセスできます。

+ +
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"
+ +

パブリックメソッド

+ +

パブリックスタティックメソッド

+ +

static キーワードは、クラスのスタティックメソッドを定義します。スタティックメソッドは、クラスのインスタンスでは呼び出されません。代わりに、クラス自体から呼び出されます。これらは、オブジェクトを作成したり、クローンを作成したりするユーティリティ関数であることが多いです。

+ +
class ClassWithStaticMethod {
+  static staticMethod() {
+    return 'static method has been called.';
+  }
+}
+
+console.log(ClassWithStaticMethod.staticMethod());
+// expected output: "static method has been called."
+ +

スタティックメソッドは、クラスの評価時に {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} を使用してクラスのコンストラクタに追加されます。これらのメソッドは書き込み可能、列挙不可、設定可能です。

+ +

パブリックインスタンスメソッド

+ +

パブリックインスタンスメソッドはその名の通り、クラスインスタンスで利用できるメソッドです。

+ +
class ClassWithPublicInstanceMethod {
+  publicMethod() {
+    return 'hello world'
+  }
+}
+
+const instance = new ClassWithPublicInstanceMethod()
+console.log(instance.publicMethod())
+// expected output: "hello worl​d"
+ +

パブリックインスタンスメソッドは、{{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} を使用して、クラスの評価時にクラスプロトタイプに追加されます。これらのメソッドは書き込み可能、列挙不可、設定可能です。

+ +

ジェネレーター関数、async、非同期ジェネレーター関数を利用することができます。

+ +
class ClassWithFancyMethods {
+  *generatorMethod() { }
+  async asyncMethod() { }
+  async *asyncGeneratorMethod() { }
+}
+ +

インスタンスメソッドの中では、this はインスタンス自体を指します。サブクラスでは、super を使用してスーパークラスのプロトタイプにアクセスし、スーパークラスからメソッドを呼び出すことができます。

+ +
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"
+
+ +

ゲッターとセッターは、クラスのプロパティにバインドする特別なメソッドで、そのプロパティがアクセスされたり設定されたりしたときに呼び出されます。get および set 構文を使用して、パブリックインスタンスのゲッターまたはセッターを宣言します。

+ +
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"
+
+ +

仕様

+ + + + + + + + + + + + + +
仕様書
{{SpecName('Public and private instance fields', '#prod-FieldDefinition', 'FieldDefinition')}}
+ +

ブラウザー実装状況

+ + + +

{{Compat("javascript.classes.public_class_fields")}}

+ +

関連情報

+ + diff --git a/files/ja/web/javascript/reference/classes/static/index.html b/files/ja/web/javascript/reference/classes/static/index.html new file mode 100644 index 0000000000..c743df4aff --- /dev/null +++ b/files/ja/web/javascript/reference/classes/static/index.html @@ -0,0 +1,132 @@ +--- +title: static +slug: Web/JavaScript/Reference/Classes/static +tags: + - Classes + - ECMAScript 2015 + - JavaScript + - Language feature + - Static +translation_of: Web/JavaScript/Reference/Classes/static +--- +
{{jsSidebar("Classes")}}
+ +

static キーワードは、クラスに静的メソッドや静的プロパティを定義します。静的メソッドも静的プロパティもクラスのインスタンスからは呼び出されません。その代わりに、クラスそのものから呼び出されます。静的メソッドは多くの場合、オブジェクトの生成や複製を行う関数などのユーティリティ関数です。静的プロパティはキャッシュ、固定的な構成、その他の各インスタンスに複製する必要のないデータです。

+ +
{{EmbedInteractiveExample("pages/js/classes-static.html")}}
+ + + +

構文

+ +
static methodName() { ... }
+static propertyName [= value];
+
+ +

+ +

クラスでの静的メンバーの使用

+ +

次の例はいくつかのことを説明しています。

+ +
    +
  1. 静的メンバー (メソッドまたはプロパティ) がクラスでどのように定義されるか
  2. +
  3. 静的メンバーを持つクラスがサブクラスを作れるか
  4. +
  5. 静的メンバーがどう呼び出せて、どう呼び出せないか
  6. +
+ +
class Triple {
+  static customName = 'Tripler';
+  static description = 'I triple any number you provide';
+  static triple(n = 1) {
+    return n * 3;
+  }
+}
+
+class BiggerTriple extends Triple {
+  static longDescription;
+  static description = 'I square the triple of any number you provide';
+  static triple(n) {
+    return super.triple(n) * super.triple(n);
+  }
+}
+
+console.log(Triple.description);   // 'I triple any number you provide'
+console.log(Triple.triple());      // 3
+console.log(Triple.triple(6));     // 18
+
+var tp = new Triple();
+
+console.log(BiggerTriple.triple(3));        // 81 (not affected by parent's instantiation)
+console.log(BiggerTriple.description);      // 'I square the triple of any number you provide'
+console.log(BiggerTriple.longDescription);  // undefined
+console.log(BiggerTriple.customName);       // 'Tripler'
+
+console.log(tp.triple());         // 'tp.triple is not a function'.
+
+ +

静的メンバーの別な静的メソッドからの呼び出し

+ +

同じクラス内の静的メソッドまたはプロパティを静的メソッドから呼び出すには、 this キーワードを使います。

+ +
class StaticMethodCall {
+  static staticProperty = 'static property';
+  static staticMethod() {
+    return 'Static method and ' + this.staticProperty + ' has been called';
+  }
+  static anotherStaticMethod() {
+    return this.staticMethod() + ' from another static method';
+  }
+}
+StaticMethodCall.staticMethod();
+// 'Static method and static property has been called'
+
+StaticMethodCall.anotherStaticMethod();
+// 'Static method and static property has been called from another static method'
+ +

クラスのコンストラクターや他のメソッドからの静的メソッドの呼び出し

+ +

静的メソッドは静的ではないメソッドの {{jsxref("this")}} キーワードを使用して直接アクセスすることができません。呼び出すにはクラス名を使用して クラス名.静的メソッド名() / クラス名.静的プロパティ名 のようにするか、 constructor プロパティのメソッドとして this.constructor.静的メソッド名() / this.constructor.静的プロパティ名 のようにしてください。

+ +
class StaticMethodCall {
+  constructor() {
+    console.log(StaticMethodCall.staticProperty); // 'static property'
+    console.log(this.constructor.staticProperty); // 'static property'
+    console.log(StaticMethodCall.staticMethod()); // 'static method has been called.'
+    console.log(this.constructor.staticMethod()); // 'static method has been called.'
+  }
+
+  static staticProperty = 'static property';
+  static staticMethod() {
+    return 'static method has been called.';
+  }
+}
+ +

仕様書

+ + + + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}
+ +

ブラウザーの互換性

+ + + +

{{Compat("javascript.classes.static")}}

+ +

関連情報

+ + -- cgit v1.2.3-54-g00ecf