メンバー変数ではなくてプロパティーについて

JavaScriptにはpublicprivate等の概念は無いですがやはり、private相当の属性にはgetterやsetterを提供してやりたくなります。

余談ですが、プラべーメンバーの隠蔽はコンストラクター内でクロージャーを使用すれば実現可能ですが他のメンバー関数からも
直接参照出来なくなるので好みではありません(命名規則などのルールで拘束すれば十分だと思ってます)。

で、getterやsetterの実装を考えると高級言語によくあるpropertyは良くできた仕様です。
内部的にsetterを定義しないかreadonlyを宣言すれば参照のみ出来るメンバー変数のできあがりです。

[C#]
{
 private int foo_;
 property int foo {
     get { return foo_; }
 };

getter,setterの実装をどうするか考えた結果、採用(別に私のオリジナルではありません)したのが以下の方法です。

Class = function() { this._foo = 0; } //privateメンバーは'_'で始める
Class.prototype.foo = function (value) {
    if(!arguments.length) {
        return this._foo;
    } else {
        this._foo = value;
    }
}

実用上これで問題ないですが、.Net Framework のPropertyGridやXmlSerializerを実装しようとすると機械的にgetter,setterの
有無を確認できる方が都合が良いです。かといって getFoo() 等にするのは嫌・・・。

で、あいだととってgetter,setterをプライベート相当で定義することにします。

Class.prototype.__foo = {}
Class.prototype.__foo.get = function() {
   return this._foo;
}
Class.prototype.foo = function (value) {
    if(!arguments.length) {
        return this.__foo.get();
    } else {
        this.__foo.set(value);  //エラー処理は割愛
    }
}

まあ、これを一つ一つ書くのは面倒なので関数を用意します。

function __property__(object, name, get, set, def) {
    var _nm = "_" + name;
    var __nm = "__" + name;
    object.prototype[_nm] = def || false;
    object.prototype[__nm] = { 'get': get, 'set': set };
    return function (value) {
        if (!arguments.length) {
            !this[__nm].get && throw new Error('has not getter');
            return this[__nm].get.apply(this);
        } else {
            !this[__nm].set && throw new Error('has not setter');
            this[__nm].set.apply(this, arguments);
        }
    };
}
Class.prototype.foo = __property__(
    Class,
    "foo", 
    function() { return this._foo; }, 
    null , 
    "hoge");
・・・やり過ぎかなorz

M. K. の紹介

IT屋さんです。プログラミングが大好きで今はJavascriptがお気に入りです。
カテゴリー: JavaScript, tips, プログラミング   タグ: ,   この投稿のパーマリンク