目次

オブジェクトなJavaScriptの基礎講座

カプセル化と継承について

◆ はじめに

普通、オブジェクト指向言語は以下の機能を実装していなくてはなりません。

  1. カプセル化
  2. 継承(inheritance)
  3. 多態性(polymorphism)

では、上記について、結構本格的なオブジェクト指向言語と言われるJavaScriptの実装を見ていきましょう。

◆ カプセル化

カプセル化とは、情報(プロパティ)や振る舞い(メソッド)をグループ化し、オブジェクトへ格納して情報を隠蔽し、さらに、振る舞いの具体的な内部処理も隠蔽することです。

プロパティ

しかし、JavaScriptでは、privateな変数すると『情報隠蔽』は出来ますが、オブジェクト毎に private な変数(情報)を保持することができず、そのため、他オブジェクトの同プロパティを変更すると、自分のプロパティの値までも変わってしまいますので、結果的に情報隠蔽ができません。

publicな変数
オブジェクトの外側から見える変数です。
コンストラクタの中で「 this.プロパティ名 」や、「クラス名.prototype.プロパティ名」とするとpublic になります。
privateな変数
外側から見えない変数です。
this を付けないと、private になります。このときには var が必要になります。
以下サンプルです。
<script type="text/javascript">
    function Point()
    {
      this.x = "width" ;  // public な変数(プロパティ)
      var y  = "height";  // private な変数。

      function _chg_y(a) {
           y = a;
      }
      Point.prototype.chg_y = _chg_y;
      function _chg_y_out() {
           return y;
      }
      Point.prototype.chg_y_out = _chg_y_out;
      return this;
    }

    // オブジェクトの作成。
    var obj = new Point();
    var obj2 = new Point();

    document.write( obj.x , "<br>" );
    document.write( obj.y , "<br>");   // private変数なので直接にはアクセスできないが...(undefined が返る)

    obj2.chg_y("koike");    //private変数をメソッドによって変更する。
    
    document.write( obj2.chg_y_out() , "<br>" );
    document.write( obj.chg_y_out() , "<br>" );  //なんと、こちらまで変更されてしまう!
  </script>
実行結果
まとめ

つまり、this で変数にするとオブジェクト毎になりますが、publicな変数(情報隠蔽でない)で、情報隠蔽ができません。また、var で変数にするとprivateな変数になり、情報隠蔽できるけど、オブジェクト毎ではなく、共用となり、結果として、情報隠蔽ができません。

つまり、privateな変数の使い道は、メソッドごとに一度初期化し、それから使い捨ての変数として利用するくらいでしょうか。

ということで、JavaScriptでのカプセル化としては、プロパティの隠蔽はできません。

メッソド

一方、メソッドは、データでなく機能ですので普通にカプセル化ができます。(これはカプセル化っていうのかなぁ...)

  function Hairetu()
  {
    function _Matrix( _row , _col )
    {
        this.length = _row;
        for ( var i = 0 ; i < _row ; ++i )
        this[i] = new Array( _col );
        return this;
    }
    Hairetu.prototype.Matrix = _Matrix;
  }

  var obj = new Hairetu();

  a = obj.Matrix(2,3);
  a[0][0] = "Chaichan";  
  a[1][2] = "Akarichan";  

  document.write( a[0][0] , "<br>");
  document.write( a[1][2] , "<br>");
実行結果
まとめ

JavaScriptでのカプセル化としては、プロパティの隠蔽はできませんが、メソッドのカプセル化は上記の感じで出来ます。

また、プロパティの隠蔽が出来なくてもJavaScriptみたいなブラウザ内部で動く小規模システムでは、あまり問題にならないと思います。たぶん。

◆ 継承

継承とは、すでに作成されているクラスの機能(メソッド、プロパティ)を新たに作成するクラスに引き継ぐことを言います。

JavaScriptでの継承は以下の感じで、子クラス(SubClass)のprototypeへnew演算子を使って親クラス(SuperClass)をコンストラタします。

function SuperClass(){
    ...
}
function SubClass(){
    ...
}
SubClass.prototype = new SuperClass ;

サンプル

以下は、親親クラスのSuperSuperClass_myMethodメソッドと親クラスのSuperClass_myMethodメソッドが子クラスに継承されているのがわかります。

    function SuperSuperClass()        // 親親クラス
    {
      function SuperSuperClass_myMethod()
      {
        document.write( "I am SuperSuperClass Method.<BR>" );
      }
      SuperSuperClass.prototype.GrandMethod = SuperSuperClass_myMethod;  //親親クラスのメソッド
    }
    
    function SuperClass()        // 親クラス
    {
      function SuperClass_myMethod()
      {
          document.write( "I am SuperClass Method.<BR>" );
      }
      SuperClass.prototype.ParentMethod = SuperClass_myMethod;   //親クラスのメソッド
    }
    SuperClass.prototype = new SuperSuperClass(); // 親親クラス継承

    function SubClass()      // 子クラス
    {
      function SubClass_myMethod()
      {
          document.write( "I am SubClass Method.<BR>" );
      }
      SubClass.prototype.MyMethod = SubClass_myMethod;
    }
    SubClass.prototype = new SuperClass(); //親クラス継承

    var oSub  = new SubClass();  //子クラスから子オブジェクトをコンストラクタする

    oSub.GrandMethod();  //継承された親親のメソッドが使える。
    oSub.ParentMethod(); //継承された親のメソッドが使える。
    oSub.MyMethod();     //子自身のメッソドがもちろん使える。

実行結果

◆ おわりに

継承を使いこなすと、いままでみたいな場当たり的なロジックを組む機会が少なくなるのでは...。また、JavaScriptのクラスライブラリを作れば、結構、需要があるかもしれません。だれか挑戦してみてください!

次回は、残りの多態性(polymorphism)である、オーバーライドと多重定義に迫ります。ご期待ください。

目次