TOTAL ACCESS 無料カウンター  UNIQUE ACCESS 無料カウンター

2009年3月13日金曜日

Javascriptで継承

Javascriptで他の言語のクラスの継承っぽいものを考えてみた
たぶん車輪の発明だろうけど気にしない気にしない

Javascripにおけるクラス(っぽいやつ)のメンバには基本的にどこからでもアクセスできるpublicなものしかありません。privateなメンバを作るにはJavascriptではクロージャを使って隠蔽するというのが定石となっています。で、今回はクロージャを使って隠蔽したprivateなメンバごと継承できるかどうか考えてみました。とりあえず以下のコードを呼んでみてください

var originalClass = function(){
  var originalPrivateVariable = 'This is a original class private variable';
  return function(){
    this.setOriginalPrivateVariable = function(x){
      originalPrivateVariable = x;
    };
    this.getOriginalPrivateVariable = function(){
      return originalPrivateVariable;
    };
    this.originalPublicVariable = 'This is a original class public variable';
  };
};

var extendedClass = function(){
  var extendedPrivateVariable = 'This is a extended class private variable';
  return function(){
    originalClass().apply(this);
    this.setExtendedPrivateVariable = function(x){
      extendedPrivateVariable = x;
    };
    this.getExtendedPrivateVariable = function(){
      return extendedPrivateVariable;
    };

    this.ExtendedPublicVariable = 'This is a extended class public variable';
  };
};

var object = new (extendedClass())();


originalClass が元のクラス、extendedClassがoriginalClassを継承したクラスです。ややこしいことになってますがこれで継承できます。もちろん継承には通常通り apply() を使っていますが、ちょっと特殊な書き方になってるのがわかるかと思います。

まずoriginalClassですがクロージャになっています。returnでラムダ関数が帰っているのでお分かりいただけると思います。クロージャですのでラムダ関数のラッパ関数(エンクロージャ)で宣言されている originalPrivateVariable も保持します。しかしここで originalClass = (function(){})() としてしまうとこの時点でのクロージャが返されてしまいますのでここでは実行しません。

そしてextendedClass。構造は1点を除きoriginalClassと同じです。違うのはreturnで返されるラムダ関数内の

originalClass().apply(this);


だけです。通常ですとapply()はhoge.apply(this)のように書きますが、applyされる時点でクロージャを形成する必要があるので一度originalClassを実行してから返されたものをapplyしているのでこのような形になります。

そして最後、インスタンスの生成。
これも上記と同じですね。生成時にクロージャを形成するので

var object = new (extendedClass())();

と言う形で書かなければならなくなります。

-----------------------------------------

さて、とりあえずコードの解説をしてきましたが、たしかに上記コードではprivateなメンバ変数にはセッタ・ゲッタからのみしかアクセスできなくなってます。しかしながら注意しなければならないことがありまして、

継承元のprivateなメンバへは継承元で定義したセッタ・ゲッタからのみしかアクセスできない

という縛りがあります。すなわち拡張したクラスでprivateなメンバ変数へのセッタ・ゲッタを増設しようとかいうことはできません。お気づきかと思いますが

継承元で定義したprivateなメンバ関数は使えなくなります。


privateにしてもこれでは意味がないですね・・・というように問題が多く残され、しかも記述もややこしくなるだけなのであまり良いことはなさそうですねというオチ。普通に書いたほうがよさそうです。しょせんクロージャはクロージャでしかないということでしょうか。またいい案が浮かべばここに書きます。