function C0( p0, p1 ){ this.p0 = p0 ; this.p1 = p1 ; } // インスタンス生成 var c0 = new C0( 1, 2 ); // write c0.p0 = 3 ; // read alert( c0.p0+", "+c0.p1 );
function MyClass( p0, p1, p3 ){ this.$p0 = p0 ; // private this.$p1 = p1 ; // private this.p3 = p3 ; // public }
$
を付けた変数は外部からアクセスするべきではないと明示した自分流の書き方です。ユーザには $
の付いた変数はメソッドを介してアクセスして下さい、または全く変更する必要はありませんなど、その旨を書いておきます。
ですが、勿論これは気休めであり、普通のインスタンス変数と何ら変わりはありません。容易に直接アクセスでき、変更可能です。
そこで、先ずはこれらのprivate
変数に関して、メソッドを介してアクセスするような方法を試みたいと思います。
function C1( p0, p1 ){ this.p0( p0 ); this.p1( p1 ); } C1.prototype.p0 = function( p ){ if( p === void 0 ){ return this.$p0 ; }else{ this.$p0 = p ; } } C1.prototype.p1 = function( p ){ if( p === void 0 ){ return this.$p1 ; }else{ this.$p1 = p ; } } var c1 = new C1( 1, 2 ); c1.p0( 3 ); // write alert( c1.p0()+", "+c1.p1() ); // read
このように private変数 $p0, $p1 に対して、メソッド p0, p1 を定義し、アクセスには全て対応するメソッドを使用するという仕組みです。
とりあえず、この形を作成しましたが、これでは private 変数が存在するだけメソッドを定義しなくてはいけず、これはかなり面倒な作業です。次にこれを自動で生成するような仕組みを考えます。
クラスの prototype オブジェクトにメソッドを自動で追加することを考えますが、ここで「全てのユーザ定義オブジェクト(クラス)は Object クラスを継承する」ことを思い出して下さい。
何やらこれでうまく行きそうですが、実際にはクラス自身(コンストラクタ関数)に関係するので Function オブジェクトを使用して以下のようになりました。
つまり、全てのコンストラクタ関数が make メソッドを保持することになります。
// private 変数にしたい変数名を引数にとり、 // それらに対するメソッドを自動生成する関数を prototype オブジェクトに追加 // 全てのコンストラクタ関数はこれを有する Function.prototype.make = function(){ for(var i=0;i<arguments.length;i++){ // 以下で対象クラスの prototype オブジェクトに追加する this.prototype[ arguments[i] ] = function( prop ){ return function( p ){ if( p === void 0 ){ return this[ '$'+prop ]; }else{ this[ '$'+prop ] = p ; } } }( arguments[i] ); } } function C2( p0, p1 ){ this.p0( p0 ); this.p1( p1 ); } // p0 と p1 は private 変数であり、ここでメソッドが追加される C2.make( "p0", "p1" ); var c2 = new C2( 1, 2 ); c2.p0( 3 ); alert( c2.p0()+", "+c2.p1() );
C2.make( "p0", "p1" )
とした時点でインスタンス変数 $p0, $p1 に対するメソッドが生成されます。やっていることは先ほどの C1 クラスのものと変わりません。勿論、Function.prototype に追加された make メソッドは汎用ですので、このあと複数のクラスを定義しても同じように make メソッドを使用できます。
Function.prototype.make = function(){
for(var i=0;i<arguments.length;i++){
this.prototype[ arguments[i] ] = function( id ){
return function( p ){
if( p === void 0 ){
return this[ id ];
}else{
this[ id ] = p ;
}
}
}( createRandomId( 8 ) );
}
// n 桁のランダムな文字列を生成する
function createRandomId( n ){
var res = "" ;
for(var i=0;i<n;i++){
switch( Math.floor( Math.random()*3 ) ){
case 0 : res += String.fromCharCode( ffCode( 48, 10 ) ); break ;
case 1 : res += String.fromCharCode( ffCode( 65, 26 ) ); break ;
case 2 : res += String.fromCharCode( ffCode( 97, 26 ) ); break ;
}
}
return res ;
function ffCode( s, d ){ return Math.floor( s+d*Math.random() ); }
}
}
function C3( p0, p1 ){
this.p0( p0 );
this.p1( p1 );
}
C3.make( "p0", "p1" );
var c3 = new C3( 1, 2 );
c3.p0( 3 );
alert( c3.p0()+", "+c3.p1() );
t8zN7fLo
とかいうランダムな変数名として仮想的に存在するわけです。