クラスのプライベートメンバー

《 初回公開:2022/11/17 , 最終更新:未 》

【 目次 】

クラスのプライベートメンバーはクラス宣言の内部からのみアクセス可能。
クラスの外部からメンバーへのアクセスの隠蔽をおこなう。
名前(識別子)の先頭に#を付ける事でプライベートフィールドだけでなく、クラス内のメソッド等のメンバーをプライベートで宣言できる。

プライベートなメンバーとしては

  • プライベートインスタンスフィールド
  • プライベート静的フィールド(プライベートクラスフィールド)
  • プライベートインスタンスメソッド
  • プライベート静的メソッド(プライベートクラスメソッド)

メソッドにはジェネレーター関数、非同期関数、非同期ジェネレーター関数を含む

プライベートメンバーを持つクラスのコード

class ClassWithPrivateMember {
  // プライベートインスタンスフィールド
  #privateField;
  // プライベートインスタンスメソッド
  #privateMethod() {
    return this.#privateField;
  }

  // プライベート静的フィールド(プライベートクラスフィールド)
  static #PRIVATE_STATIC_FIELD;
  // プライベート静的メソッド(プライベートクラスメソッド)
  static #privateStaticMethod() {
    return this.#PRIVATE_STATIC_FIELD;
  }
}

in演算子とプライベートフィールド

in 演算子を使用すると、プライベートフィールド (またはプライベートメソッド) が欠けているかどうかをチェックできます。
そのプライベートフィールドが存在すれば true を返し、そうでなければ false を返します。

前出のClassWithPrivateMemberクラスのコードを以下のように変更。

class ClassWithPrivateMember {
  // プライベートインスタンスフィールド
  #privateField = "private";
  // プライベートインスタンスメソッド
  #privateMethod() {
    return this.#privateField;
  }

  // プライベート静的フィールド(プライベートクラスフィールド)
  static #PRIVATE_STATIC_FIELD = "PRIVATE_STATIC";
  // プライベート静的メソッド(プライベートクラスメソッド)
  static #privateStaticMethod() {
    return this.#PRIVATE_STATIC_FIELD;
  }

  publicMethod() {
    // クラスのインスタンスは#privateFieldと#privateMethodを含んでいる
    console.log(#privateField in this
      && #privateMethod in this);   // true
    // #PRIVATE_STATIC_FIELDはクラスのメンバーであってインスタンスのメンバーではない
    console.log(#PRIVATE_STATIC_FIELD in this); // false
    // ClassWithPrivateMemberクラスは#PRIVATE_STATIC_FIELDを含んでいる
    console.log(#PRIVATE_STATIC_FIELD in ClassWithPrivateMember);   // true

    // インスタンスメソッドからプライベートメンバーにアクセス
    return this.#privateMethod();
  }
  static publicStaticMethod() {
    // #PRIVATE_STATIC_FIELDと#privateStaticMethodはクラスのメンバー
    console.log(#PRIVATE_STATIC_FIELD in this
      && #privateStaticMethod in this); // true

    // クラスメソッドからプライベートなクラスのメンバーにアクセス
    return this.#privateStaticMethod();
  }
}
let obj = new ClassWithPrivateMember();
console.log(obj.publicMethod());    // private
let result = ClassWithPrivateMember.publicStaticMethod();
console.log(result); // PRIVATE_STATIC

このコードはin演算子を使ってクラスやインスタンスのメンバーが含まれているかを示すサンプルコードであると同時に、クラス内からプライベートメンバーにどのようにアクセスするかを示している。

このプライベートメンバーに対するin演算子の使い方は通常のパブリックなプロパティに対する使い方と異なっている点に注意する必要がある。

class MyCls {
  publicField = "public";
  #privateField = "private";

  method() {
    console.log(#privateField in this); // true
    console.log("publicField" in this); // true

    console.log(Object.getOwnPropertyNames(this));  // ['publicField']
  }
}
let myObj = new MyCls();
myObj.method();

パブリックなプロパティでは引用符で囲む必要があるのにプライベートメンバーではそれが無い。
また、この例でわかるようにObject.getOwnPropertyNamesではプライベートメンバーは現れない。

プライベートメンバーの制限

プライベートメンバーはそれを定義したクラス外からはアクセスできないという制限があるのは当然だが、静的フィールドには更に制限があるようで。

プライベート静的フィールドには制限があります。プライベート静的フィールドを定義したクラスのみが、そのフィールドにアクセスできます。this を使用すると、予期しない動作をする可能性があります。

上記のコードのpublicStaticMethodは、実はClassWithPrivateMemberを継承したクラスからpublicStaticMethodメソッドにアクセスするとエラーが発生する。

class SubClass extends ClassWithPrivateMember { };
//  次の行でUncaught TypeError: Receiver must be class ClassWithPrivateMember at SubClass.publicStaticMethod
SubClass.publicStaticMethod();

スーパークラスのstaticメソッド内のthisをそれを継承したクラスから呼び出すと、thisは継承先のクラスSubClsを示していてTypeError が発生するようだ。

thisは呼び出し元のクラスを指す

class SuperCls {
  static method() {
    console.log(this.name);
  }
}
class SubCls extends SuperCls { }

SuperCls.method();  // SuperCls
SubCls.method();    // SubCls

従って以下のようにpublicStaticMethod内のthisを、直接クラスを示すClassWithPrivateMemberに置き換えるとエラーが発生しなくなる。

static publicStaticMethod() {
  // #PRIVATE_STATIC_FIELDと#privateStaticMethodはクラスのメンバー
  console.log(#PRIVATE_STATIC_FIELD in ClassWithPrivateMember
    && #privateStaticMethod in ClassWithPrivateMember); // true

  // クラスメソッドからプライベートなクラスのメンバーにアクセス
  return ClassWithPrivateMember.#privateStaticMethod();
}

プライベート静的メソッドにも同様の事が言えて

class SuperClass {
  static #privateStaticMethod() {   }
  static publicStaticMethod() {
    this.#privateStaticMethod();
  }
};
class SubClass extends SuperClass { };
SubClass.publicStaticMethod();

上記コードのハイライト行を以下のように修正する事で解決できる。

SuperClass.#privateStaticMethod();

ちょっとわかりずらそうなので、プライベート静的フィールドのthisによるエラーの例をもう一つ。

class SuperCls {
  #privateField = "private";

  method() {
    console.log(this.#privateField);
  }
}

class SubCls extends SuperCls { }

let subObj=new SubCls();
subObj.method();    // private

上記のコードではエラーは発生しないが、このSuperClsのメンバーをstaticに変更すると同じようにTypeErrorが発生する。

class SuperCls {
  static #privateField = "private";

  static method() {
    console.log(this.#privateField);
  }
}

class SubCls extends SuperCls { }

SubCls.method();

これも前述の例と同じように上記コードのハイライト行のthisを以下のようにSuperClsに変更する事でエラーは発生しなくなる。

console.log(SuperCls.#privateField);
ページのトップへ戻る