人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

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;
}
}

●質問者: kameoyaji_2
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● lang_and_engine
●50ポイント

プロパティ定義は、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


lang_and_engineさんのコメント
こちらの最初のFooのサンプルみたいに、 prototype内でクロージャの性質を使ってgetter/setterを作るほうが、JSらしいやり方です。 これなら、firefox以外のどのブラウザでも動作が保証されます。 http://d.hatena.ne.jp/kazu-yamamoto/20071101/1193884132

2 ● rikuba
●150ポイント ベストアンサー

今のところは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]);

kameoyaji_2さんのコメント
ほぼ、希望する動きは出来たのですが、追加で何点かご指導いただけないでしょうか? 言語の特性で無理なのかもしれないのですが、 下記の様に書き直した時 var fun = new abc(2, 3); alert([fun.a, fun.b, fun.c]); // "2,3," cがundefindの為 ? fun.a = 4; alert([fun.a, fun.b, fun.c]); // "4,3," cがundefindの為 ? function abc(arg1, arg2) { this.a = arg1; this.b = arg2; } Object.defineProperties(abc.prototype, { // ? <途中省略> }); 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" ?の場所にalertを追加した時に希望する動作をしないのです。 ?のObject.definePropertiesを実行する前なので当たり前と言えば当たり前なのですが、 function abc(…)の中で定義することは可能でしょうか?(注記1参照) (jvascriptの読み込む順番等が変わっても、期待する動作にさせたいもので) function calcab(arg1, arg2) をグローバル関数になっているのですが、これを クラス内の関数に定義することは可能でしょうか? abc.prototype = { calcab: function (arg1, arg2){ var Result = 0; try { Result = parseInt(arg1) * parseInt(arg1); } catch (ex){ throw "calcab invalid data"; } return Result; } } (上記みたいな感じになるのかな・・などと考えています。) まだまだ、javascript初心者の為、javasciptの考え方が理解しておりません、 ご指導いただければ有りがたいです。 (javascript言語を勉強中の者です) 注記1 function abc(arg1, arg2) { Object.defineProperties(this.prototype, { <途中省略> }); this.a = arg1; this.b = arg2; } に改造してみたり(Uncaught TypeError. Object.defineProperties called on on-object で実行できませんでしたが) abc.prototype = { a: { get: function () { return this._a; }, set: function (value) { this._a = value; this._c = this.calcab(value, this.b); }, configurable: true, enumerable: true }, <省略> } としてみたりしては、いるのですが、思い通り作ることが出来ておりません。 ブラウザ等は最新版以外は動作を考えていません。 検証&デバックはChrome DevTools を使用しております。

rikubaさんのコメント
「<i>クラス</i>定義とメインコードを明確に分離し、<i>クラス</i>定義→メインコードの順で実行されるようにする」とした方がいいと思います。 >|html| <script src="abc.js"></script> <script> (function () { // 即時関数 var fun = new abc(2, 3); // 省略 })(); </script> ||< そうはいかない理由があるのであれば、コンストラクタ関数内ですべてのプロパティを定義してしまえば手っ取り早いです。グローバル変数として定義したくない<code>calcab</code>も関数内に突っ込んでしまえばしまいです。 ただし、<code>abc</code>関数が呼び出される度に<code>defineProperty</code>の処理であったり<code>calcab</code>関数の実体化であったりが行われるため、何百・何千と<i>インスタンス</i>が作られるような<i>クラス</i>では避けた方が良いでしょう。 また、コンストラクタ関数内がしっちゃかめっちゃかになってしまうのもいまいちだと思います。 >|javascript| 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などの依存関係を解決するためのライブラリについて調べてみると解決できるかもしれません。

kameoyaji_2さんのコメント
ありがとうございます。 思い通りの処理が実現できました。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ