[JavaScript] アクセサプロパティ:JavaScript 1.8.5、ECMAScript 5

Rubyのアクセサメソッド、C#やActionScript 3.0のプロパティと同じ、getter/ setter用のアクセサ機能が、JavaScriptでも1.8.5ですでに定義されている。

使い方

オブジェクトの宣言時

アクセサとして使う関数をfunctionではなくget/ setで宣言する。

var obj = {
	x_	: 1,
	get x() {
		return this.x_;
	},
	set x(value) {
		this.x_ = value;
	}
};

get/ setは、それぞれひとつのプロパティなのでコンマ「,」で区切る。

アクセサとプロパティを同名にはできないので、プロパティのほうを「x_」という名前にしている。

これで普通は十分だと思うが、x_が外部からアクセスできてしまうことを防ぎたい場合は、クロージャのローカル変数を使う。

var obj = (function () {
	var x_;
	
	return {
		get x() {
			return x_;
		},
		set x(value) {
			x_ = value;
		}
	};
})();

この手法は、prototypeを使ってクラスをつくる場合は使えない。

(function () {
	function Sample() {
		// コンストラクタ
	}
	
	var x_;
	
	Sample.prototype = {
		get x() {
			return x_;
		},
		set x(value) {
			x_ = value;
		}
	};
})();

この場合、x_はプライベートな静的変数のような扱いになるので、複数のインスタンスで共通のものとなる。

外部からアクセスできてしまうが、「Sample.prototype.x_」として使うしかない。

オブジェクトの生成後、あとから追加

Object.defineProperty()」を使う。

Object.defineProperty(obj, prop, descriptor)

obj			: プロパティを定義する対象のオブジェクト
prop		: 定義するプロパティ名
descriptor	: プロパティの属性をオブジェクトで定義
var obj = {
	x_	: 1
};

Object.defineProperty(obj, "x", {
	get	: function () {
		return this.x_;
	},
	set	: function (value) {
		this.x_ = value;
	}
});

なお、ECMAScript 5では通常のプロパティ=データプロパティ(data property)を書き込み不可にできる。

これを利用すればgetterのようにもできるが、一切の書き込みを不可にするので一種の定数のようになる。

var obj = {};

Object.defineProperty(obj, "x", {
	value		: 1,
	writable	: false
});
ディスクリプタ

プロパティの属性を定義したオブジェクトのことをディスクリプタと呼ぶ。

フィールド名 タイプ 説明 デフォルト値
configurable 共通 ディスクリプタの変更、プロパティの削除を許可 false
enumerable 共通 列挙可能か(for inなどで) false
value データ プロパティの値 undefined
writable データ プロパティの値を変更可能か false
get アクセサ getter undefined
set アクセサ setter undefined

データディスクリプタとアクセサディスクリプタは混在できない。

まとめ

オブジェクトの生成時に同時に定義する場合は、「get () {}」の形式。

オブジェクトの生成後に追加で定義する場合は、「get : function () {}」の形式。