February 12, 2008
またしても野望の会ブログに反応してみる。
http://www.yabooo.org/archives/53
JavaScriptではC++やJavaと違ってprivateなインスタンス変数や,メソッドが定義できないのでなんとかしましょうという話。
同じようなことがPerlでもやられていて,Perl Hacksでは裏返しオブジェクトというのが紹介されています。上記のエントリーと同じ発想で,クロージャを使うわけですがオブジェクトの保存場所が微妙に違います。JavaScriptでやるとこんな感じ?
var Class = {
'create': function (tmpl) {
var repos = [];
var klass = function () {
this._id = repos.length;
repos.push({});
tmpl.initialize.apply(repos[this._id], arguments);
};
for (var i in tmpl) {
if (i == 'initialize') continue;
if (typeof tmpl[i] == 'function')
klass.prototype[i] = function () {
return tmpl[i].apply(repos[this._id], arguments);
};
}
klass.extend = function (obj) {
for (var i in obj) {
klass.prototype[i] = function () {
return obj[i].apply(repos[this._id], arguments);
};
}
};
return klass;
}
};
var Foo = Class.create({
'initialize' : function () {
this.x = 100;
},
'getX' : function () {
return this.x;
}
});
var foo = new Foo;
print(foo.getX()); // 100
print(foo.x); // undefined
メソッドは全部パブリックだし,いろいろ手抜きだけどとりあえず隠蔽はできてます。クラスのコンストラクタそのものをクロージャにしてしまうとこがポイントですね。
メソッドはprototype経由で呼び出されるので,オブジェクトをnewする度に発生する,メモリ消費のオーバヘッドもありません(たぶん
さらに,あとからメソッドを追加したくなった場合は
Foo.extend({
'printX' : function () {
print(this.x);
}
});
foo.printX(); // 100
とかできて,うれしい気持ち…。
