アクセサプロパティの基本
プロパティには、データプロパティとアクセサプロパティの2種類がある。
必ずどちらかに分類でき、両方の性質を兼ね備えることは出来ない。
データプロパティには値が格納される。
アクセサプロパティは、値は持たず、getterやsetterと呼ばれる関数を設定する。両方の関数を設定することも出来るし、片方だけ設定するということも可能。
以下の例では、_nameをデータプロパティとして、nameをアクセサプロパティとして、それぞれ設定している。
var person = { _name:'Tom', get name(){ console.log('_nameを読み込みます'); return this._name; }, set name(value){ console.log('_nameに'+value+'を書き込みます'); this._name = value; } }; console.log(person.name); // _nameを読み込みます // Tom person.name = 'Bob'; // _nameにBobを書き込みます console.log(person.name); // _nameを読み込みます // Bob
nameの値を読もうとするとgetterが呼ばれ、nameに値を代入しようとすると、setterが呼ばれる。
そのため、setterには必ず引数が必要。引数を取らない形でsetterを定義すると、エラーになる。
一方で、getterにreturnを設定しなくても、エラーにはならない。その場合はundefinedが戻り値になる。
getterのないアクセサプロパティを読み込もうとすると、undefinedが返ってくる。
setterのないアクセサプロパティに書き込みをしようとすると、無視され、何も起こらない。strictモードでは、エラーとなる。
// getterがない var person1 = { _name:'Tom', set name(value){ console.log('_nameに'+value+'を書き込みます'); this._name = value; } }; console.log(person1.name); // undefined // setterがない var person2 = { _name:'Tom', get name(){ console.log('_nameを読み込みます'); return this._name; } }; console.log(person2.name); // _nameを読み込みます // Tom person2.name = 'Bob'; // 何も起こらない strictモードだと、ここでエラーになる console.log(person2.name); // _nameを読み込みます // Tom
プロパティの内部属性によるgetterとsetterの設定
データプロパティにはなく、アクセサプロパティだけが持つ内部属性に[[Get]]と[[Set]]がある。それぞれ、getter関数とsetter関数を格納する。
この属性を操作することによって、getterとsetterを追加したり、内容を変更したりすることが出来る。
先ほどのコードの記法では、オブジェクト生成時にしか、getterやsetterを定義できなかった。
プロパティの内部属性の操作を行えるdefineProperty()については、下記を参照。
プロパティの内部属性
// 生成した時点では、personはアクセサプロパティを持たない var person = { _name:'Tom' }; Object.defineProperty(person, 'name', { get: function(){ console.log('_nameを読み込みます'); return this._name; }, configurable: true // この属性がtrueでないと、nameプロパティを後から操作することは出来ない }); console.log(person.name); // _nameを読み込みます // Tom // ここで、getterを上書きしつつ、setterを設定する Object.defineProperty(person, 'name', { get: function(){ console.log('これは、新しく設定されたgetterです'); return this._name; }, set: function(value){ console.log('_nameに'+value+'を書き込みます'); this._name = value; } }); person.name = 'Bob'; // _nameにBobを書き込みます console.log(person.name); // これは、新しく設定されたgetterです // Bob