class【クラス】

メモ ( 概要 サブクラス化 private フィールド private メソッド public フィールド public メソッド static ブロック )
構文 ( クラス宣言クラス式)

メモ

概要

  • 他言語の class 相当
    • 関数ベースで実装 (typeof で型判定:'function')
    • クラス宣言 または クラス式 で定義
    • new で生成
    • クラス内は、strict モード で実行
    • 巻き上げなし (クラスの使用前に、クラス定義が必要:ReferenceError 例外)
    • インスタンスはオブジェクトで、対応クラスは instanceof で判定
    • 他言語の protected 相当はなし
  • クラス宣言構文〕〔
  • クラス式構文〕〔
    • クラス名は省略可
    • 再宣言可

サブクラス化

  • extends を指定
  • 標準組込みオブジェクトの継承可能
  • 親クラスの呼び出し
    • 親のコンストラクタが存在する場合、super( ~ ) で明示的に呼び出し
    • 親メソッドは、super.親メソッド( ~ ) で呼び出し

コンストラクタ構文

  • constructor で単一定義 (複数定義:SyntaxError 例外)
  • サブクラスでは親コンストラクタは、super( ~ ) で明示的に呼び出し (this 参照前に処理)
  • this は生成中のオブジェクト

private フィールド構文

  • 複数定義可
    • 後から追加は不可
  • 参照前に要定義
  • static 指定で静的フィールド
  • in 演算子で存在確認可

private メソッド構文

  • 複数定義可
    • 後から追加は不可
  • 参照前に要定義
  • static 指定で静的メソッド

public フィールド構文

  • クラス内に定義可
    • 複数定義可
  • static 指定で静的フィールド
  • 動的に作成可 (インスタンス フィールド)
    • コンストラクタ・static なしのメソッド内で、this.public フィールド名に値代入 (this:インスタンス)
    • クラスの外部で クラス名.prototype.public フィールド名に値代入
  • 動的に作成可 (static フィールド)
    • static メソッド・static ブロックで、クラス名.public フィールド名に値代入
    • クラスの外部で クラス名.public フィールド名に値代入

public メソッド構文

  • 複数定義可
  • static 指定で静的メソッド
  • 動的に作成可 (インスタンス メソッド)
    • コンストラクタ・static なしのメソッド内で、this.public メソッドに関数代入 (this:インスタンス)
    • クラスの外部で クラス名.prototype.public メソッド名に関数代入
  • 動的に作成可 (static メソッド)
    • static メソッド・static ブロックで、クラス名.public メソッドに関数代入
    • クラスの外部で クラス名.public メソッド名に関数代入

static ブロック構文

  • クラス評価で一度だけ処理
  • 複数定義可 (宣言順に処理)
  • static フィールド の初期化に評価値が可能
  • 親クラスの static ブロック は サブクラスの初期化の前に処理

構文
(クラス宣言クラス式)

// クラス宣言
class クラス名[ extends 親クラス名] {
    // コンストラクタ (単一定義)
    [constructor([引数]) {コンストラクタ処理}]

    // private フィールド (複数定義可)
    [[static ]#フィールド名[= 初期値];] 

    // private メソッド (複数定義可)
    [[static ]#メソッド名([引数]) {メソッド処理}] 
    [[static ]*#ジェネレータメソッド名([引数]) {ジェネレータメソッド処理}] 
    [[static ]async #非同期メソッド名([引数]) {非同期メソッド処理}] 
    [[static ]async *#非同期ジェネレータメソッド名([引数]) {非同期ジェネレータメソッド処理}] 
    [[static ]get #プロパティ名 ( ) {ゲッター処理}] 
    [[static ]set #プロパティ名 (設定値) {セッター処理}] 

    // public フィールド (複数定義可)
    [[static ]フィールド名[= 初期値];] 

    // public メソッド (複数定義可)
    [[static ]メソッド名([引数]) {メソッド処理}]
    [[static ]*ジェネレータメソッド名([引数]) {ジェネレータメソッド処理}]
    [[static ]async 非同期メソッド名([引数]) {非同期メソッド処理}]
    [[static ]async *非同期ジェネレータメソッド名([引数]) {非同期ジェネレータメソッド処理}]
    [[static ]get プロパティ名 ( ) {ゲッター処理}]
    [[static ]set プロパティ名 (設定値) {セッター処理}]

    // static ブロック (複数定義可・クラス利用で一度だけ定義順に処理)
    [static {static ブロック処理}] 
}
// クラス式
変数 = class[ クラス名][ extends 親クラス名] { クラス内定義 (クラス定義と同等) }

基本

// 巻き上げなし
// const dummy = new MyClass();
// 例外 ReferenceError: can't access lexical declaration 'MyClass' before initialization

// クラス宣言
class MyClass {
  publicField = 'Public Field (MyClass)';
}
// 再宣言不可
// class MyClass { }
// 例外 Uncaught SyntaxError: Identifier 'MyClass' has already been declared

console.log(typeof MyClass);
// 出力:function
let obj = new MyClass();
console.log(obj instanceof MyClass);
// 出力:true
console.log(typeof obj);
// 出力:object
console.log(obj.publicField);
// 出力:Public Field (MyClass)

// クラス式 (クラス名指定)
let MyClass2 = class MyClass002 {
  publicField = 'Public Field (MyClass002) Old';
};
// 再宣言可
MyClass2 = class MyClass002 {
  publicField = 'Public Field (MyClass002)';
};
console.log(typeof MyClass2);
// 出力:function
obj = new MyClass2();
console.log(obj instanceof MyClass2);
// 出力:true
console.log(obj.publicField);
// 出力:Public Field (MyClass002)

// クラス式 (クラス名省略)
const MyClass3 = class {
  publicField = 'Public Field (Unknown)';
};
obj = new MyClass3();
console.log(obj instanceof MyClass2);
// 出力:false
console.log(obj instanceof MyClass3);
// 出力:true
console.log(obj.publicField);
// 出力:Public Field (Unknown)

サブクラス化

class Parent {
  publicFieldParent = 'Public Field (Parent)';

  // コンストラクタ
  constructor() {
    console.log('Parent:constructor()');
  }
  // スタティック ブロック
  static {
    console.log('Static Block (Parent)');
  }
}
// 出力:Static Block (Parent)

class Child extends Parent {
  publicFieldChild = 'Public Field (Child)';

  // コンストラクタ
  constructor() {
    console.log('Child:constructor()');
    super();
  }
  // スタティック ブロック
  static {
    console.log('Static Block (Child)');
  }
}
// 出力:Static Block (Child)

const obj = new Child();
// 出力:Child:constructor()
// 出力:Parent:constructor()
console.log(obj.publicFieldParent);
// 出力:Public Field (Parent)
console.log(obj.publicFieldChild);
// 出力:Public Field (Child)
console.log(obj instanceof Parent);
// 出力:true
console.log(obj instanceof Child);
// 出力:true

コンストラクタ
private フィールド
private メソッド
public フィールド
public メソッド

class MyClass {
  // コンストラクタ
  constructor() {
    console.log('constructor()');
    this.publicFieldInner1 = 'Public Field Inner 1';
    this.publicMethodInner1 = () => { console.log('publicMethodInner1( )'); }
  }

  // private フィールド
  #privateField = 'Private Field';
  static #privateStaticField = 'Private Static Field';

  // private メソッド
  #privateMethod() {
    console.log('#privateMethod( )');
    return this.#privateField;
  }
  static #privateStaticMethod() {
    console.log('#privateStaticMethod( )');
    return this.#privateStaticField;
  }

  // public フィールド
  publicField = 'Public Field';
  static publicStaticField = 'Public Static Field';

  // public メソッド
  publicMethod() {
    console.log('publicMethod( )');
    this.publicFieldInner2 = 'Public Field Inner 2';
    this.publicMethodInner2 = () => { console.log('publicMethodInner2( )'); }
  }
  static staticPublicMethod() {
    console.log('staticPublicMethod( )');
    MyClass.publicStaticFieldInner1 = 'Public Static Field Inner 1';
    MyClass.publicStaticMethodInner1 = () => { console.log('publicStaticMethodInner1( )'); }
  }
  // public メソッド (セッター・ゲッター)
  get publicProperty() {
    console.log('get publicProperty( )');
    return this.publicPropertyValue;
  }
  set publicProperty(value) {
    console.log('set publicProperty( )');
    this.publicPropertyValue += ' -> ' + value;
  }
  // public メソッド (プライベート アクセス)
  getPrivateField() {
    console.log('getPrivateField( )');
    return this.#privateMethod();
  }
  static getPrivateStaticField() {
    console.log('getPrivateStaticField( )');
    return MyClass.#privateStaticMethod();
  }

  // static ブロック
  static {
    console.log('Static Block 1');
    MyClass.publicStaticFieldInner2 = MyClass.publicStaticField + ' Inner 2';
    MyClass.publicStaticMethodInner2 = () => { console.log('publicStaticMethodInner2( )'); }
  }
  static {
    console.log('Static Block 2');
  }
}
// 出力:Static Block 1
// 出力:Static Block 2

// 外部設定
MyClass.staticPublicMethod();
// 出力:staticPublicMethod( )
MyClass.prototype.publicFieldOuter = 'Public Field Outer';
MyClass.prototype.publicMethodOuter = () => { console.log('publicMethodOuter( )'); }
MyClass.publicStaticFieldOuter = 'Public Static Field Outer';
MyClass.publicStaticMethodOuter = () => { console.log('publicStaticMethodOuter( )'); }

// public フィールド (static)
console.log(MyClass.publicStaticField);
// 出力:Public Static Field
console.log(MyClass.publicStaticFieldInner1);
// 出力:Public Static Field Inner 1
console.log(MyClass.publicStaticFieldInner2);
// 出力:Public Static Field Inner 2
console.log(MyClass.publicStaticFieldOuter);
// 出力:Public Static Field Outer

// public メソッド (static)
let value = MyClass.getPrivateStaticField();
// 出力:getPrivateStaticField( )
// 出力:#privateStaticMethod( )
console.log(value);
// 出力:Private Static Field
MyClass.publicStaticMethodInner1();
// 出力:publicStaticMethodInner1( )
MyClass.publicStaticMethodInner2();
// 出力:publicStaticMethodInner2( )
MyClass.publicStaticMethodOuter();
// 出力:publicStaticMethodOuter( )

// インスタンス生成
const obj = new MyClass();
// 出力:constructor()

// public フィールド
console.log(obj.publicField);
// 出力:Public Field
console.log(obj.publicFieldInner1);
// 出力:Public Field Inner 1
obj.publicMethod();
// 出力:publicMethod( )
console.log(obj.publicFieldInner2);
// 出力:Public Field Inner 2
console.log(obj.publicFieldOuter);
// 出力:Public Field Outer

// public メソッド
obj.publicMethodInner1();
// 出力:publicMethodInner1( )
obj.publicMethodInner2();
// 出力:publicMethodInner2( )
obj.publicMethodOuter();
// 出力:publicMethodOuter( )
obj.publicProperty = 'publicProperty';
// 出力:set publicProperty( )
console.log(obj.publicProperty);
// 出力:get publicProperty( )
// 出力:undefined -> publicProperty
value = obj.getPrivateField();
// 出力:getPrivateField( )
// 出力:#privateMethod( )
console.log(value);
// 出力:Private Field

#x in obj

class MyClass {
  #privateField = 'Private Field';

  static isRelated(obj) {
    return #privateField in obj;
  }
}

class YourClass {
  #privateField = 'Private Field';
}

const myObj = new MyClass();
console.log(MyClass.isRelated(myObj));
// 出力:true
const yourObj = new YourClass();
console.log(MyClass.isRelated(yourObj));
// 出力:false