ECMAScript コードで、内部プロパティもどきを有するコンストラクタの作成を模索する。
直付けのメソッドでローカル変数参照すりゃいいじゃん。
function CF (p0) { var v0 = p0; // 隠蔽したい変数 this.get_v0 = function (){ return v0; }; this.set_v0 = function (p0){ v = p0; }; }
じゃぁ、 this 直下のプロパティじゃなくて、プロパティのプロパティにする。
function CF (p0) { var p = new Object; p.v0 = p0; // 隠蔽したい変数 this.p = p; } CF.prototype.getValue = function (name) { return this.p[name]; }; CF.prototype.setValue = function (name, value) { this.p[name] = value; };
何とかしてローカル変数をプロトタイプの関数から参照したい。
function CF (p0) { var p = new Object; p.v0 = p0; // 隠蔽したい変数 } CF.prototype.getValue = function (name) { return p[name]; }; CF.prototype.setValue = function (name, value) { p[name] = value; };
p をコンストラクタとその prototype の関数で共有したいから、コンストラクタの外から参照できるようにしよう。
P = new Object; function CF (p0) { var p = new Object; p.v0 = p0; // 隠蔽したい変数 this.id = '$'+parseInt(Math.pow(10,20)*Math.random()); P[this.id] = p; } CF.prototype.getValue = function (name) { return P[this.id][name]; }; CF.prototype.setValue = function (name, value) { P[this.id][name] = value; };
全体をさらに関数内に入れて P を外部アクセス不可にしよう。コンストラクタは改めて window オブジェクトのプロパティに設定すればいい。
気休めに、 id に用いるプロパティ名を乱数で発生させ、プロパティ名のバッティングの可能性を下げる。
function initCF () { var P = new Object, id = '$'+parseInt(Math.pow(10,20)*Math.random()), n=0; function CF (p0) { var p = new Object; p.v0 = p0; // 隠蔽したい変数 this[id] = '$' + n + parseInt(100*Math.random()); n++; P[this[id]] = p; } CF.prototype.getValue = function (name) { return P[this[id]][name]; }; CF.prototype.setValue = function (name,value) { P[this[id]][name] = value; }; window.CF = CF; };initCF();
というわけで initCF を delete することを考える。ここでは initCF 自体を CF という名前で定義し、 自分自身の呼出し時に参照する関数をコンストラクタに置き換えることにした。あとは好みで表記を若干修正。
function CF () { // ----------(1) var P = new Object, id = '$'+ parseInt(Math.pow(10,20)*Math.random()), n=0; // p を取得する関数を生成: function getPrivate (o) { return P[ o[id] ]; }; // コンストラクタ: 祖先コンテキストの CF、つまり(1) を置き換える CF = function (p0) { this[id] = '$' + n + parseInt(100*Math.random()); n++; var p = P[ this[id] ] = new Object; p.v0 = p0; // 隠蔽したい変数 } // プロトタイプ定義 CF.prototype.getValue = function (name) { // var p = getPrivate(this); とすることで // コンストラクタ関数のローカル変数 p を取得できる return getPrivate(this)[name]; }; CF.prototype.setValue = function (name,value) { getPrivate(this)[name] = value; }; };CF();
function CF () { var P = new Object, id = '$'+parseInt(Math.pow(10,20)*Math.random()), n=0; function getPrivate (o) { return P[o[id]]; }; CF = function (p0,p1) { this[id] = '$' + n + parseInt(100*Math.random()); n++; var p = P[this[id]] = new Object; p.v0 = p0; p.v1 = p1; } CF.prototype.getValue = function (name) { return getPrivate(this)[name]; }; CF.prototype.setValue = function (name,value) { getPrivate(this)[name] = value; }; };CF(); var o = new CF('てすと1', 'てすと2'); var p = new CF('テスト1', 'テスト2'); document.writeln( 'o.getValue("v0") = ' + o.getValue('v0') ); document.writeln( 'o.getValue("v1") = ' + o.getValue('v1') ); document.writeln( 'p.getValue("v0") = ' + p.getValue('v0') ); document.writeln( 'p.getValue("v1") = ' + p.getValue('v1') ); document.writeln( ); o.setValue('v0', 'TEST1'); o.setValue('v1', 'TEST2'); p.setValue('v0', 'test1'); p.setValue('v1', 'test2'); document.writeln( 'o.getValue("v0") = ' + o.getValue('v0') ); document.writeln( 'o.getValue("v1") = ' + o.getValue('v1') ); document.writeln( 'p.getValue("v0") = ' + p.getValue('v0') ); document.writeln( 'p.getValue("v1") = ' + p.getValue('v1') ); document.writeln( ); for (i in o){ document.writln( 'o.'+i+' = ' + o[i] ); } for (i in p){ document.writln( 'p.'+i+' = ' + p[i] ); }