現代的JavaScriptおれおれアドベントカレンダー2017 – 05日目
getter/setterとは、普通のプロパティのように見えて実は関数、てなやつです。 document.cookie
がそれ的な感じですね。最近あんまり使わない気がするけど。
使い方
まずこんな感じで get xxx
と set xxx
を定義しまして。
var obj = { get name() { console.log('get()', this._name); return this._name; }, set name(value) { const sValue = String(value); const name = sValue.charAt(0).toUpperCase() + sValue.slice(1).toLowerCase(); // capitalize console.log('set()', this._name, '->', name); this._name = name; }, };
使う側は普通のプロパティと同様にアクセスします。
obj.name = 'alice'; console.log('Name:', obj.name); // "Alice" obj.name = 'BOB'; console.log('Name:', obj.name); // "Bob"
値保持用のプロパティ
を別途、関数の外に持っていないといけないのがちょっとアレ。
JavaScript村では「アンダースコアから始まるプロパティはprivateなものとみなす」という昔からの風習があるので、それを利用するとよろしいかと存じます。
obj._name
とか書いちゃうのは駄目ということになっている、ってことです。
delete
で削除も
できます。
delete obj.name; obj.name = 'cHARLIE'; console.log(obj.name); // "cHARLIE"
普通のプロパティと一緒ですね。
後から追加する
既に存在するオブジェクトでも、 Object.defineProperty()
を使ってgetter/setterを追加できます。
var obj = {}; Object.defineProperty(obj, 'name', { get() { console.log('get()', this._name); return this._name; }, set(value) { const sValue = String(value); const name = sValue.charAt(0).toUpperCase() + sValue.slice(1).toLowerCase(); // capitalize console.log('set()', this._name, '->', name); this._name = name; }, });
obj.name = 'alice'; console.log('Name:', obj.name); // "Alice" obj.name = 'BOB'; console.log('Name:', obj.name); // "Bob"
他にも enumerable
とか、いろいろ機能があります。個人的にはget/setだけ知ってれば良いかなーとか思ってます。
あ、ちなみに value
というのもあるんだけど、get/setで扱う値を保持する用途ではないです。
メソッドの書き方
さりげなく書きましたけど、 function
の記述を省略することができます。
var obj = { foo() {}, function bar() {}, };
別稿参照。
クラスで使う
クラスでもget/setを書けます。
class Person { constructor(name) { this.name = name; } get name() { console.log('get()', this._name); return this._name; } set name(value) { const sValue = String(value); const name = sValue.charAt(0).toUpperCase() + sValue.slice(1).toLowerCase(); // capitalize console.log('set()', this._name, '->', name); this._name = name; } }
var obj = new Person('alice'); console.log('Name:', obj.name); obj.name = 'bob'; console.log('Name:', obj.name);
その他
ES2015 (ES6) じゃなくてES5.1(2011年)で追加されました。
でもどうしてもお伝えしたくて。ごめんね。
あと両方を作る必要はないです。setterだけとか全然アリです。
参考
- ECMAScript 2015 Language Specification – ECMA-262 6th Edition
- 7.3.7 DefinePropertyOrThrow (O, P, desc) …
Object.defineProperty()
の仕様、だと思う - 9.1.6 [[DefineOwnProperty]] (P, Desc) …
Object.defineProperty()
の第三引数の扱いについて、だと思う - 14.3 Method Definitions … get/setの書式
- 7.3.7 DefinePropertyOrThrow (O, P, desc) …
- getter – JavaScript | MDN
- setter – JavaScript リダイレクト 1 | MDN … あれ、なんかタイトルとURLが変?
- Object.defineProperty() – JavaScript | MDN … 日本語版は『不完全』らしい