【JavaScript】 ゲッター/セッター関数を後から変更する方法
更新日:2021/02/01
使用する状況があまりなさそうだけれど、ゲッターとセッターの動作を別の関数に置き換える方法がないか考えてみました。
ゲッター/セッターに関する非推奨メソッド
JavaScriptがブラウザ上で動作する場合、標準オブジェクトに次のメソッドが追加されています。
__defineGetter__ : ゲッターを定義する
__defineSetter__ : セッターを定義する
__lookupGetter__: ゲッター関数を取得する
__lookupSetter__: セッター関数を取得する
使用例
// セッターの追加
obj.prototype.__defineSetter__(
"prop2", // プロパティ名
function( v ){ this._v = v; } // 呼び出す関数
);
// ゲッターの追加
obj.prototype.__defineGetter__(
"prop2", // プロパティ名
function( ){ return this._v; } // 呼び出す関数
);
しかし、これらのメソッドはレガシー機能として位置付けられ、非推奨となっています。
ゲッター/セッターの推奨定義方法
オブジェクトにゲッターとセッターを定義するとき、Object.definePropertyメソッドを使用することが推奨されています。
let value = 100;
Object.defineProperty(
obj.prototype , // 追加先のオブジェクト
"prop2" , // プロパティ名
{
set : function( v ){ value = v; },
get : function( ){ return value; },
configurable:true,
}
)
このメソッドは、プロパティのconfigurable属性がfalseでなければ、再度呼び出すことで呼び出す関数を変更することができます。
Object.defineProperty(
obj.prototype , // 追加先のオブジェクト
"prop2" , // プロパティ名
{
set : function( v ){ value = v * 100; },
configurable:true,
}
);
このとき、setまたはgetのみの指定も可能です。
指定されなかった方は、そのまま残ります。
ゲッター/セッター関数を取得して変更する
__lookupGetter__と__lookupSetter__が非推奨となりゲッターおよびセッター関数を取得するメソッドができなくなりました。
そこで他の方法で、取得してみます。
次のコードでプロパティの情報を取得します。
const ds = Object.getOwnPropertyDescriptor( オブジェクト, プロパティ名 );
取得した情報は、次のようなオブジェクトになっています。
get: 関数/undefined ,
set: 関数/undefined,
enumerable: true/false,
configurable: true/false
}
getとsetプロパティがundefinedでなければ、それが目的の関数となります。
プロパティがゲッター・セッターでない場合、オブジェクトにgetとsetがありません。
これらがあるかどうかをチェックすることで、プロパティが通常のものかどうかを確認することも可能です。
このオブジェクトは、そのままObject.definePropertyで使用できます。
getまたはsetプロパティに現在と異なる関数をセットすれば、ゲッター・セッターを変更できます。
変更例
function getObj(){
let val=0;
return {
get val1(){
return val;
},
set val1(v){
val = v;
},
};
}
const obj = getObj();
const ds = Object.getOwnPropertyDescriptor(obj, "val1");
ds.get = ()=>300;
Object.defineProperty(obj, "val1", ds);
console.log( obj.val1 ); // 300
上の使用例を見てもらうと、変更後のゲッター関数は300を返しています。
ゲッター関数の変更理由として、戻り値の計算方法を変えたいということがあります。
そこで、val * 2 などを返したかったのですが、これは不可能でした。
理由については、次のページを読んでみてください。
【JavaScript】 JSにおけるカプセル化手法
実際のところ、ゲッターとセッターを変更するとコードを追うことが非常に難しくなります。
そのため、取得値の変更等は関数内でフラグ等で管理すべきです。
また、ゲッターとセッターを変更するコードが第三者によって組み込まれる可能性があります。
重要なオブジェクトはObject.freeze()等で凍結することを検討したほうがいいですね。
更新日:2021/02/01
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。