JavaScript プライベートフィールド

概要: このチュートリアルでは、JavaScript のプライベートフィールドと、それらを効果的に使用する方法について学習します。

JavaScript プライベートフィールドの紹介

ES2022 では、クラスにプライベートフィールドを定義できます。プライベートフィールドを定義するには、フィールド名の前に#記号を付けます。

たとえば、次の例は、プライベートフィールドradiusを持つCircleクラスを定義しています。

class Circle {
  #radius;
  constructor(value) {
    this.#radius = value;
  }
  get area() {
    return Math.PI * Math.pow(this.#radius, 2);
  }
}Code language: JavaScript (javascript)

この例では

  • まず、クラス本体にプライベートフィールド#radiusを定義します。
  • 次に、コンストラクタで引数を用いて#radiusフィールドを初期化します。
  • 次に、ゲッターメソッドで#radiusプライベートフィールドにアクセスして円の面積を計算します。

次の例では、Circleクラスの新しいインスタンスを作成し、その面積を計算しています。

let circle = new Circle(10);
console.log(circle.area); // 314.1592653589793Code language: JavaScript (javascript)

#radiusはプライベートフィールドであるため、Circleクラス内でのみアクセスできます。つまり、#radiusフィールドはCircleクラスの外部からは見えません。

ゲッターとセッターを使用してプライベートフィールドにアクセスする

次の例では、radiusゲッターとセッターを追加して#radiusプライベートフィールドへのアクセスを提供することにより、Circleクラスを再定義しています。

class Circle {
  #radius = 0;
  constructor(radius) {
    this.radius = radius; // calling setter
  }
  get area() {
    return Math.PI * Math.pow(this.#radius, 2);
  }
  set radius(value) {
    if (typeof value === 'number' && value > 0) {
      this.#radius = value;
    } else {
      throw 'The radius must be a positive number';
    }
  }
  get radius() {
    return this.#radius;
  }
}Code language: JavaScript (javascript)

動作方法。

  • radiusセッターは、引数を#radiusプライベートフィールドに代入する前に、引数を検証します。引数が正の数でない場合、radiusセッターはエラーをスローします。
  • radiusゲッターは、#radiusプライベートフィールドの値を返します。
  • コンストラクタはradiusセッターを呼び出して、引数を#radiusプライベートフィールドに代入します。

プライベートフィールドとサブクラス

プライベートフィールドは、定義されているクラス内でのみアクセス可能です。また、サブクラスからもアクセスできません。たとえば、次の例は、拡張するCylinderクラスを定義していますCircleクラス

class Cylinder extends Circle {
  #height;
  constructor(radius, height) {
    super(radius);
    this.#height = height;

    // cannot access the #radius of the Circle class here
  }
}Code language: JavaScript (javascript)

Cylinderクラスで#radiusプライベートフィールドにアクセスしようとすると、SyntaxErrorが発生します。

in 演算子:プライベートフィールドの存在を確認する

クラス内でオブジェクトにプライベートフィールドがあるかどうかを確認するには、in演算子を使用します。

fieldName in objectName

たとえば、次の例では、in演算子を使用してcircleオブジェクトに#radiusプライベートフィールドがあるかどうかを確認するhasRadius()静的メソッドをCircleクラスに追加しています。

class Circle {
  #radius = 0;
  constructor(radius) {
    this.radius = radius;
  }
  get area() {
    return Math.PI * Math.pow(this.radius, 2);
  }
  set radius(value) {
    if (typeof value === 'number' && value > 0) {
      this.#radius = value;
    } else {
      throw 'The radius must be a positive number';
    }
  }
  get radius() {
    return this.#radius;
  }
  static hasRadius(circle) {
    return #radius in circle;
  }
}

let circle = new Circle(10);

console.log(Circle.hasRadius(circle));
Code language: JavaScript (javascript)

出力

trueCode language: JavaScript (javascript)

静的プライベートフィールド

次の例は、静的プライベートフィールドの使用方法を示しています。

class Circle {
  #radius = 0;
  static #count = 0;
  constructor(radius) {
    this.radius = radius; // calling setter
    Circle.#count++;
  }
  get area() {
    return Math.PI * Math.pow(this.radius, 2);
  }
  set radius(value) {
    if (typeof value === 'number' && value > 0) {
      this.#radius = value;
    } else {
      throw 'The radius must be a positive number';
    }
  }
  get radius() {
    return this.#radius;
  }
  static hasRadius(circle) {
    return #radius in circle;
  }
  static getCount() {
    return Circle.#count;
  }
}

let circles = [new Circle(10), new Circle(20), new Circle(30)];

console.log(Circle.getCount());
Code language: JavaScript (javascript)

動作方法。

まず、Circleクラスにプライベート静的フィールド#countを追加し、その値をゼロに初期化します。

static #count = 0;Code language: JavaScript (javascript)

次に、コンストラクタで#countを1増やします。

Circle.#count++;Code language: JavaScript (javascript)

次に、#countプライベート静的フィールドの値を返す静的メソッドを定義します。

static getCount() {
    return Circle.#count;
}Code language: JavaScript (javascript)

最後に、Circleクラスのインスタンスを3つ作成し、countの値をコンソールに出力します。

let circles = [new Circle(10), new Circle(20), new Circle(30)];
console.log(Circle.getCount());
Code language: JavaScript (javascript)

まとめ

  • フィールド名を#記号で接頭辞として付けると、プライベートになります。
  • プライベートフィールドは、クラス内でのみアクセス可能であり、クラス外またはサブクラスからはアクセスできません。
  • in演算子を使用して、オブジェクトにプライベートフィールドがあるかどうかを確認します。
このチュートリアルは役に立ちましたか?