昔書いたものですが、再利用します。オブジェクト思考だから。 前に書いたOOJS続きです。

Javascriptでの継承とオーバーライド

前回Javascriptでのオブジェクト指向プログラミングを見てきました。 今回は継承とオーバーライドについてお話します。Javascriptでは継承はcall()とapply()を使います。

call()メソッドを使った継承の例

下のコードを見てみてください。
<html>
<body>
<script type="text/javascript">
function Person(_name, _email) {
  this.name = _name;
  this.email = _email;
  this.show = function () {
    document.writeln("  名前      : " +  this.name + "</br>");
    document.writeln("  Eメール : " +  this.email + "</br><hr>");
  }
}
function Manager(_name, _email, _roll) {
  Person.call(this, _name, _email);
  this.roll = _roll
  this.show = function () {
    document.writeln("  名前      : " +  this.name + "</br>");
    document.writeln("  Eメール : " +  this.email + "</br>");
    document.writeln("  役職        : " +  this.roll + "</br><hr>");
  }
}
var taro = new Person("太郎", "taro@example.com");
taro.show();
var hanako = new Manager("花子", "hanako@example.com", "部長");
hanako.show();
</script>
</body>
</html>
Person関数はnameとemailというプロパティを持っています。また、プロパティを表示するshow()というメソッドを持っています。 ここで、役職を持っているAdminという関数が必要になったとします。 役職を識別するrollというプロパティが新たに必要です。勿論Adminにもnameとemailはあるでしょう。 こういった場合、Personを継承してAdminという関数(クラス)を作るのが良いです。
function Manager(_name, _email, _roll) {
  Person.call(this, _name, _email);
  this.roll = _roll
  this.show = function () {
    document.writeln("  名前      : " +  this.name + "</br>");
    document.writeln("  Eメール : " +  this.email + "</br>");
    document.writeln("  役職        : " +  this.roll + "</br><hr>");
  }
}
ポイントは、Person関数をcall()メソッドで読んでいる所です。 call()メソッドはFunctionオブジェクトが持つメソッドで、関数に引数を渡しています。また、showメソッドを上書きしています。 継承元の関数を、継承した関数で上書きすることをオーバーライドと言います。 これでオブジェクト指向プログラミングのポリモフィズムは実現できそうです。 ただし、オーバライドを含む継承の際にはcall()を呼ぶ場所に注意してください。試しに下記コードを実行してみてください。 call()を呼ぶ位置を一番下にしてみました。
function Manager(_name, _email, _roll) {
  this.roll = _roll
  this.show = function () {
    document.writeln("  名前      : " +  this.name + "</br>");
    document.writeln("  Eメール : " +  this.email + "</br>");
    document.writeln("  役職        : " +  this.roll + "</br><hr>");
  }
  Person.call(this, _name, _email);
}
Person関数のなかでもthis.showプロパティにファンクションを代入しているため、showがオーバーライドされてしまっていますね? ほとんどの場合、は先頭で呼んでおけば問題は無いと思います。

apply()メソッドを使った継承の例

ほとんどcall()の場合と変わりません。
<html>
<body>
<script type="text/javascript">
function Person(_name, _email) {
  this.name = _name;
  this.email = _email;
  this.show = function () {
    document.writeln("  名前      : " +  this.name + "</br>");
    document.writeln("  Eメール : " +  this.email + "</br><hr>");
  }
}
function Manager() {
  Person.apply(this, arguments);
  this.roll = arguments[2];
  this.show = function () {
    document.writeln("  名前      : " +  this.name + "</br>");
    document.writeln("  Eメール : " +  this.email + "</br>");
    document.writeln("  役職        : " +  this.roll + "</br><hr>");
  }
}
var taro = new Person("太郎", "taro@example.com");
taro.show();
var hanako = new Manager("花子", "hanako@example.com", "部長");
hanako.show();
</script>
</body>
</html>
apply()メソッドは可変長引数に対応しています。 但し、IEではサポートしていないので、注意が必要です。

Javascriptでのオーバーロード

Javascriptではオーバーロードは可能でしょうか? オーバーロードとは、同じ名前のメソッドですが引数の数を変えることで、別のメソッドとして扱う事です。 下のコードはJavaでのオーバーロードの例です。
class hoge() {
  // 省略
  void example(String strVal) {
    // 処理1
  }
  void example(String strVal, int intVal) {
    // 処理2
  }
}
上記の様な同名のメソッドが合った場合、example("文字列")と呼び出せば、処理1が実行されます。example("文字列", 1)と呼び出された場合、処理2が実行されます。感の良い皆様はおわかりだと思いますが、Javascriptにおいてはオーバーロードは実装出来ません。 Javascriptのメソッドはあくまでプロパティと同じ扱いなので、上記の用に書いた場合、2個目のファンクションで1つめのファンクションが上書きされてしまいます。 Javaにおいてはメソッドを識別するのに、メソッド名と引数の定義を使っています。コレをメソッド・ディスクリプタと言います。 Javascriptではプロパティ名としか認識していませんし、可変長引数が有るため、引数の定義でメソッドを識別出来ないためですね。誠に残念ではありますが、此処は泣いて馬謖を斬るしか有りません。 これでオブジェクト指向プログラミングの最低限の道具はそろいました。