技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

JavaScript:オブジェクト指向らしい記述をする

JavaScriptではオブジェクト指向がサポートされています。
JavaC#に触れている方であればお馴染みだと思いますが、オブジェクト指向を用いることで規模が大きいプログラムを作る時の生産性が向上します。
 
以下では、インスタンス生成と、ポリモーフィズム(複数のサブクラスを同じように使う)を試してみます。
Node.jsを使用して実行します。
(ES2015以降の書き方となります)
 
【サンプルコード】
・test.js
// クラスの定義
class Log {
 
  // コンストラクタの定義
  constructor(name) {
    this.name = name;
  }
 
  // メソッドの定義
  log(message) {
    console.log(this.name + ":" + message);
  }
}

// クラスの継承
class DecoratedLog extends Log {
 
  // コンストラクタの定義(継承元のコンストラクタ呼び出し)
  constructor(name) {
    super(name);
  }
 
  // メソッドのオーバーライド
  log(message) {
    console.log(this.name + ":*** " + message + " ***");
  }
}

// 継承でまた別のクラスを定義
class RichLog extends Log {
 
  constructor(name) {
    super(name);
  }
 
  log(message) {
    console.log(this.name + ":[unknown] " + message);
  }
 
  // 継承したクラスに新たなメソッドを定義
  infoLog(message) {
    console.log(this.name + ":[info] " + message);
  }
}

// オブジェクトを生成
let myLog1 = new Log("ログ1");
let myLog2 = new Log("ログ2");
let myDecoratedLog = new DecoratedLog("デコったログ");
let myRichLog = new RichLog("リッチなログ");

// オブジェクトを配列に格納
let objects = [];
objects.push(myLog1);
objects.push(myLog2);
objects.push(myDecoratedLog);
objects.push(myRichLog);

// 処理を実行
// ループ処理中でポリモーフィズムの実現を確認できる
// 継承先のクラスでしか定義していないメソッドも使用できている
myRichLog.infoLog("start");
for (let i = 0; i < objects.length; i++) {
  objects[i].log("hello World!");
}
myRichLog.infoLog("end");
 
【実行結果】
リッチなログ:[info] start
ログ1:hello World!
ログ2:hello World!
デコったログ:*** hello World! ***
リッチなログ:[unknown] hello World!
リッチなログ:[info] end
 
---------------------
 
ちなみに、ES2015より前のバージョンではこの書き方はできません。
オブジェクト指向をプログラム言語で実現する上で、「クラスベース」と呼ばれる概念と「プロトタイプベース」と呼ばれる概念があるのですが、ES2015より前のバージョンでは「プロトタイプベース」と呼ばれる概念に基づく書き方をする必要があります。
JavaC#は「クラスベース」と呼ばれる概念に基づく書き方をするので、JavaC#の経験者にとってはとっつきにくいと思います。
 
なお、ES2015以降はクラスベースに基づく書き方が可能になっていますが、内部的にはプロトタイプベースに基づく処理をしています。
例えば、クラス名の型を調べると、"class"ではなく"function"になるのですが、これはプロトタイプベースの名残です。