概要
オブジェクトのプロパティには属性があります。
属性は大きく分けて「書き込み可能」「列挙可能」「再定義可能」などがあります。
また、アクセサプロパティのゲッターメソッドとセッターメソッドをプロパティ属性として考えるとすると、アクセサプロパティには書き込み可能属性がないと言えます。
データプロパティの属性は、値も属性のひとつとみなし、書き込み可能、列挙可能、再定義可能、の合計4つの属性があると言えます。
(アクセサプロパティには値の属性はないものと考えます)
まとめるとアクセサプロパティは、ゲッター、セッター、列挙可能、再定義可能、の4つの属性があると言えます。
プロパティのメタ属性の取得と設定
上記の概要で書いた4つの属性について、プロパティディスクリプタと呼ばれるオブジェクトを使います。
プロパティディスクリプタはプロパティのメタ属性と言え、データアクセスに対しての取り決めを決定しています。
データプロパティについては、次のようなメタ属性の名前を持ちます。
value
writable
enumerable
configurable
また、アクセサプロパティについては、次のようなメタ属性を持ちます。
get
set
enumerable
configurable
アクセサプロパティは、valueとwritableのメタ属性はありません。
試しに、前回の投稿で書いたサンプルコードに対して、プロパティディスクリプタオブジェクトを取得して試してみます。
var test = {
a: '10',
b: '20',
get access_a() {
return this.a;
}
}
//プロパティディスクリプタオブジェクトを使用してtestオブジェクトのプロパティを出力
console.log(Object.getOwnPropertyDescriptor(test, 'a'));
上記のサンプルコードを実行した結果は次のようになります。
{…}
configurable: true
enumerable: true
value: "10"
writable: true
<prototype>: {…}
__defineGetter__: function __defineGetter__()
__defineSetter__: function __defineSetter__()
__lookupGetter__: function __lookupGetter__()
__lookupSetter__: function __lookupSetter__()
constructor: function Object()
hasOwnProperty: function hasOwnProperty()
isPrototypeOf: function isPrototypeOf()
propertyIsEnumerable: function propertyIsEnumerable()
toLocaleString: function toLocaleString()
toSource: function toSource()
toString: function toString()
valueOf: valueOf()
ブラウザの開発ツールの出力なので、出力結果がまとめられている箇所があり、出力結果のオープン/クローズで表示されるので一部抜粋しています。
上記の出力結果では
configurable: true
enumerable: true
value: "10"
writable: true
という先ほどあげたメタ属性についての記述があります。
また、上記の結果から、testオブジェクトのaプロパティは、データプロパティであることがわかります。(get、setが無く、valueやwritable属性が表示されています)
また、getOwnPropertyDescriptor()の処理対象はオブジェクトに対して独自プロパティのみが対象となります。
継承されたプロパティ等は対象ではない為に、継承オブジェクトには明示的にgetOwnPropertyDescriptor()を書く必要があります。
definePropertyについて
ここまでは、getOwnPropertyDescriptorを使ってオブジェクトのプロパティを調べる形でしたが、
オブジェクトのプロパティに対して、属性を設定(変更)するメソッドについても調べてみます。
オブジェクトに対してプロパティの属性を変更するには、
defineProperty
を使います。
書き方は
Object.defineProperty()
という形になり、()内で設定したいオブジェクトと、プロパティ名、それと属性(上記でいうメタ属性)を設定します。
具体的には、次のようになります。
var test = {
a: '10',
b: '20',
get access_a() {
return this.a;
}
}
//definePropertyを使用して属性の変更
Object.defineProperty(test, 'a', {
value: '30',
writable: false,
});
//testオブジェクトのプロパティaに対し、文字列40を代入する
test.a = '40';
//内容を確認
console.log(test.a); //出力結果「30」
上記の例はtestオブジェクトのプロパティaに対して、メタ属性を変更しています。また、値の設定についても同時に行っています。
出力結果については、「30」と出力され、writableでfalseにしている為、値の代入を行っても書き変わらない挙動になります。
以上のように、オブジェクトのプロパティに対しての属性の設定を簡単に試してみました。
上記以外の命令や書き方があるので、ブログに追記する形で更新いたします。