javascript でclassを構築して、オブジェクト プロパティに セッタ・ゲッタ設定できないものでしょうか?

下記のようなソースを作っては見たものの、期待した動きができていません、ご指導いただけないでしょうか。


var fun = new abc(2,3);
alert(fun.a); // 2を期待
alert(fun.b); // 3を期待
alert(fun.c); // 6を期待
fun.a = 4;
alert(fun.a); // 4を期待
alert(fun.b); // 3を期待
alert(fun.c); // 12を期待

function abc(arg1,arg2){
this.a ={
_value:0,
get function(){
return this._value;
},
set function(val){
this._value = val;
this.c = calcab(this._value, this.a);
}
};
this.b ={
_value:0,
get function(){
return this._value;
},
set function(val){
this._value = val;
this.c = calcab(this.a, this._value);
}
};
this.a = arg1;
this.b = arg2;

function calcab(arg1, arg2){
return arg1 * arg2;
}
}

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2013/12/27 18:46:33
  • 終了:2013/12/29 18:27:09

ベストアンサー

id:rikuba No.2

rikuba回答回数26ベストアンサー獲得回数122013/12/27 23:55:48

ポイント150pt

今のところはECMAScript5で標準化されたObject.create, Object.defineProperty, Object.definePropertiesを使ってください。
なお、IE8以下ではこれらのメソッドは定義されておらず、getter, setterを定義する方法はありません(IE8はDOMオブジェクトに限り__defineGetter__, __defineSetter__によってgetter, setterを定義することができます)。

function abc(arg1, arg2) {
    this.a = arg1;
    this.b = arg2;
}

Object.defineProperties(abc.prototype, {
    a: {
        get: function () {
            return this._a;
        },
        set: function (value) {
            this._a = value;
            this.c = calcab(value, this.b);
        },
        configurable: true,
        enumerable: true
    },
    b: {
        get: function () {
            return this._b;
        },
        set: function (value) {
            this._b = value;
            this.c = calcab(this.a, value);
        },
        configurable: true,
        enumerable: true
    }
});

function calcab(arg1, arg2) {
    return arg1 * arg2;
}

var fun = new abc(2, 3);
alert([fun.a, fun.b, fun.c]); // "2,3,6"

fun.a = 4;
alert([fun.a, fun.b, fun.c]); // "4,3,12"

cをgetterにしてみる。

function Abc(a, b) {
    this.a = a;
    this.b = b;
}

Object.defineProperty(Abc.prototype, 'c', {
    get: function () {
        return this.a * this.b;
    },
    configurable: true,
    enumerable: true
});

var fun = new Abc(2, 3);
alert([fun.a, fun.b, fun.c]);

fun.a = 4;
alert([fun.a, fun.b, fun.c]);
他1件のコメントを見る
id:rikuba

クラス定義とメインコードを明確に分離し、クラス定義→メインコードの順で実行されるようにする」とした方がいいと思います。

<script src="abc.js"></script>
<script>
(function () { // 即時関数
    var fun = new abc(2, 3);
    // 省略
})();
</script>

そうはいかない理由があるのであれば、コンストラクタ関数内ですべてのプロパティを定義してしまえば手っ取り早いです。グローバル変数として定義したくないcalcabも関数内に突っ込んでしまえばしまいです。
ただし、abc関数が呼び出される度にdefinePropertyの処理であったりcalcab関数の実体化であったりが行われるため、何百・何千とインスタンスが作られるようなクラスでは避けた方が良いでしょう。
また、コンストラクタ関数内がしっちゃかめっちゃかになってしまうのもいまいちだと思います。

var fun = new abc(2, 3);
alert([fun.a, fun.b, fun.c]); // "2,3,6"

fun.a = 4;
alert([fun.a, fun.b, fun.c]); // "4,3,12"

function abc(arg1, arg2) {
    Object.defineProperties(this, {
        a: {
            get: function () {
                return this._a;
            },
            set: function (value) {
                this._a = value;
                this.c = calcab(value, this.b);
            },
            configurable: true,
            enumerable: true
        },
        b: {
            get: function () {
                return this._b;
            },
            set: function (value) {
                this._b = value;
                this.c = calcab(this.a, value);
            },
            configurable: true,
            enumerable: true
        }
    });
    
    function calcab(arg1, arg2) {
        return arg1 * arg2;
    }
    
    // コンストラクタとしての処理はここで
    this.a = arg1;
    this.b = arg2;
}

私は使った経験がないため解説できませんが、Require.jsなどの依存関係を解決するためのライブラリについて調べてみると解決できるかもしれません。

2013/12/28 13:17:19
id:kameoyaji_2

ありがとうございます。
思い通りの処理が実現できました。

2013/12/29 18:25:57

その他の回答(1件)

id:language_and_engineering No.1

lang_and_engine回答回数170ベストアンサー獲得回数632013/12/27 21:00:34

ポイント50pt

プロパティ定義は、new時にthisに対して行うのではなく、newよりも前の時点でprototype属性に対して行います。
その時点でget/setキーワードを利用します。
(これらのキーワードはブラウザ依存だし、javascriptらしいやり方ではなくC#のコードみたいに見えますし、それに使わなくてもクラスは作れるので、余りおすすめはしません。)
new時には、(定義ではなく)実際の値の代入処理をしましょう。

下記のサンプルコードが役立つと思いますが。
http://hondou.homedns.org/pukiwiki/pukiwiki.php?Javascript%20get%2Fset%20%B1%E9%BB%BB%BB%D2

id:language_and_engineering

こちらの最初のFooのサンプルみたいに、
prototype内でクロージャの性質を使ってgetter/setterを作るほうが、JSらしいやり方です。
これなら、firefox以外のどのブラウザでも動作が保証されます。

http://d.hatena.ne.jp/kazu-yamamoto/20071101/1193884132

2013/12/27 21:06:18
id:rikuba No.2

rikuba回答回数26ベストアンサー獲得回数122013/12/27 23:55:48ここでベストアンサー

ポイント150pt

今のところはECMAScript5で標準化されたObject.create, Object.defineProperty, Object.definePropertiesを使ってください。
なお、IE8以下ではこれらのメソッドは定義されておらず、getter, setterを定義する方法はありません(IE8はDOMオブジェクトに限り__defineGetter__, __defineSetter__によってgetter, setterを定義することができます)。

function abc(arg1, arg2) {
    this.a = arg1;
    this.b = arg2;
}

Object.defineProperties(abc.prototype, {
    a: {
        get: function () {
            return this._a;
        },
        set: function (value) {
            this._a = value;
            this.c = calcab(value, this.b);
        },
        configurable: true,
        enumerable: true
    },
    b: {
        get: function () {
            return this._b;
        },
        set: function (value) {
            this._b = value;
            this.c = calcab(this.a, value);
        },
        configurable: true,
        enumerable: true
    }
});

function calcab(arg1, arg2) {
    return arg1 * arg2;
}

var fun = new abc(2, 3);
alert([fun.a, fun.b, fun.c]); // "2,3,6"

fun.a = 4;
alert([fun.a, fun.b, fun.c]); // "4,3,12"

cをgetterにしてみる。

function Abc(a, b) {
    this.a = a;
    this.b = b;
}

Object.defineProperty(Abc.prototype, 'c', {
    get: function () {
        return this.a * this.b;
    },
    configurable: true,
    enumerable: true
});

var fun = new Abc(2, 3);
alert([fun.a, fun.b, fun.c]);

fun.a = 4;
alert([fun.a, fun.b, fun.c]);
他1件のコメントを見る
id:rikuba

クラス定義とメインコードを明確に分離し、クラス定義→メインコードの順で実行されるようにする」とした方がいいと思います。

<script src="abc.js"></script>
<script>
(function () { // 即時関数
    var fun = new abc(2, 3);
    // 省略
})();
</script>

そうはいかない理由があるのであれば、コンストラクタ関数内ですべてのプロパティを定義してしまえば手っ取り早いです。グローバル変数として定義したくないcalcabも関数内に突っ込んでしまえばしまいです。
ただし、abc関数が呼び出される度にdefinePropertyの処理であったりcalcab関数の実体化であったりが行われるため、何百・何千とインスタンスが作られるようなクラスでは避けた方が良いでしょう。
また、コンストラクタ関数内がしっちゃかめっちゃかになってしまうのもいまいちだと思います。

var fun = new abc(2, 3);
alert([fun.a, fun.b, fun.c]); // "2,3,6"

fun.a = 4;
alert([fun.a, fun.b, fun.c]); // "4,3,12"

function abc(arg1, arg2) {
    Object.defineProperties(this, {
        a: {
            get: function () {
                return this._a;
            },
            set: function (value) {
                this._a = value;
                this.c = calcab(value, this.b);
            },
            configurable: true,
            enumerable: true
        },
        b: {
            get: function () {
                return this._b;
            },
            set: function (value) {
                this._b = value;
                this.c = calcab(this.a, value);
            },
            configurable: true,
            enumerable: true
        }
    });
    
    function calcab(arg1, arg2) {
        return arg1 * arg2;
    }
    
    // コンストラクタとしての処理はここで
    this.a = arg1;
    this.b = arg2;
}

私は使った経験がないため解説できませんが、Require.jsなどの依存関係を解決するためのライブラリについて調べてみると解決できるかもしれません。

2013/12/28 13:17:19
id:kameoyaji_2

ありがとうございます。
思い通りの処理が実現できました。

2013/12/29 18:25:57

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません