getter/setterとは
以下のようにオブジェクトのpropertyにget/setを付けることにより、
プロパティの呼び出し時やプロパティへの値の代入時に関数が呼び出されるようになる。
正確には、getあるいはsetを付けるとpropetyの記述子が特別な「アクセサー記述子」になる。
(通常のpropertyはデータ記述子)
const hoge ={
get hoge(){
return "hoge";
}
set hoge(h) {
console.log(h);
}
}
hoge.hoge//hoge
hoge.hoge = "fuga"//consoleにfugaと出る
クロージャと組み合わせてオブジェクトのカプセル化やWrapperオブジェクトの作成に使える。
getterの挙動
getterの挙動は一見、通常のデータ記述子に対するアクセスするのと変わらない。
オブジェクト宣言中でgetterを定義した場合、通常アクセスの外、
スプレッド構文やfor...inループにも表れる。
getter、setter内で同名プロパティにアクセスした場合
getterやsetterはJavaなどの言語におけるgetterやsetterと異なり、
そのプロパティに紐づくもの自体をアクセサーに変える。
よって下記のようなコードは無限ループを引き起こす
get hoge(){
return this.hoge;
}
getterやsetterを片方しか定義しなかった場合の挙動
getterしかないpropertyに値を代入しようとした場合には何も起こらない。
(そのプロパティが通常のデータ記述子型プロパティに変わったりはしない)
同様にsetterしかないプロパティに対して値を読みだそうとするとundefinedになる。
getterかsetterを一つでも定義した時点で、そのpropertyはアクセサー型のpropertyになるので、
未定義の側もデータ記述子型のように扱うことは出来ない。
消したい場合、更新したい場合
- deleteを用いればpropertyごと消えるので、getter/setter共に消滅する deleteにはpropertyの種類がデータ記述かアクセサー記述かは関係ない
- 上書きしたい場合はObject.definePropertyあるいはObject.definePropertiesを利用する。
- 上記のdefineProperty系はプロパティの属性ごと書き換えることが可能なので、アクセサ型のpropertyの書き換えも可能。
- かつては
Object.__defineGetter__
とかdefineSetterもあったが非推奨になった - definePropertyを使うことで後からgetterやsetterの追加も可能。ただし、definePropertyをデフォルトオプションで使ってPropertyを追加すると、通常のプロパティ宣言とかなり挙動が異なる。(キーが列挙されない、書き換え不可になるなど)注意が必要