Object.defineProperty()メソッドは、オブジェクトに新しいプロパティを直接定義したり、既存のプロパティを変更したりする際に使用します。このメソッドは変更されたオブジェクト(最初の引数obj)を返します。
構文:
Object.defineProperty(obj, prop, descriptor)
<br></br>//obj:プロパティを定義する対象のオブジェクト
//prop:定義または変更するプロパティの名前
//descriptor:定義または変更するプロパティの記述子<br></br><br></br>
Vue.jsはObject.definePropertyを利用して双方向データバインディングを実現しています。
オブジェクトのプロパティに特性を追加する方法として、現在2つの形式が提供されています:データ記述子とアクセサ記述子です。
データ記述子
オブジェクトのプロパティを変更または定義する際に、そのプロパティにいくつかの特性を追加します。
value: プロパティの値を設定 writable: 値を上書きできるかどうか。true | false enumerable: プロパティを列挙できるかどうか。true | false configurable: プロパティを削除できるか、または特性を再度変更できるかどうか。true | false
value:プロパティに対応する値。任意の型の値が可能で、デフォルトはundefinedです。
let data = {}
//ケース1:valueプロパティを設定しない場合
Object.defineProperty(data, "newKey", {
});
console.log(data.newKey); //undefined
------------------------------
//ケース2:valueプロパティを設定する場合
Object.defineProperty(data, "newKey", {
value: "こんにちは"
});
console.log(data.newKey); //こんにちは
writable:プロパティの値を上書きできるかどうか。デフォルトはfalseで、trueに設定すると上書きできます。
let user = {};
Object.defineProperty(user, 'location', {
value: '東京'
//writableはデフォルトでfalse、プロパティ値は変更不可
});
user.location = '大阪';
console.log(user.location); //undefined
let user = {};
Object.defineProperty(user, 'location', {
value: '東京',
writable: true
});
user.location = '大阪';
console.log(user.location); //大阪
enumerable:このプロパティを列挙できるかどうか。
trueに設定すると列挙可能になります。falseに設定すると列挙できません(デフォルトはfalse)。
var sample = {}
//ケース1:enumerableをfalseに設定すると、列挙できません。
Object.defineProperty(sample, "newKey", {
value: "こんにちは",
writable: false,
enumerable: false
});
//オブジェクトのプロパティを列挙
for (var attr in sample) {
console.log(attr);
}
//ケース2:enumerableをtrueに設定すると、列挙可能です。
Object.defineProperty(sample, "newKey", {
value: "こんにちは",
writable: false,
enumerable: true
});
//オブジェクトのプロパティを列挙
for (var attr in sample) {
console.log(attr); //newKey
}
configurable:プロパティを削除できるか、または特性を再度変更できるかどうか。
trueに設定すると削除または特性の再設定が可能です。falseに設定すると設定できません。
このプロパティの役割:
- プロパティをdeleteで削除できるかどうか
- プロパティの特性を再度設定できるかどうか
//-----------------プロパティが削除可能かどうかのテスト------------------------
var testObj = {}
//ケース1:configurableをfalseに設定すると、削除できません。
Object.defineProperty(testObj, "newKey", {
value: "こんにちは",
writable: false,
enumerable: false,
configurable: false
});
//プロパティを削除
delete testObj.newKey;
console.log(testObj.newKey); //こんにちは
//ケース2:configurableをtrueに設定すると、削除できます。
Object.defineProperty(testObj, "newKey", {
value: "こんにちは",
writable: false,
enumerable: false,
configurable: true
});
//プロパティを削除
delete testObj.newKey;
console.log(testObj.newKey); //undefined
//-----------------特性を再度変更できるかどうかのテスト------------------------
var testObj = {}
//ケース1:configurableをfalseに設定すると、特性を再度変更できません。
Object.defineProperty(testObj, "newKey", {
value: "こんにちは",
writable: false,
enumerable: false,
configurable: false
});
//特性を再度変更
Object.defineProperty(testObj, "newKey", {
value: "こんにちは",
writable: true,
enumerable: true,
configurable: true
});
console.log(testObj.newKey); //エラー:Uncaught TypeError: Cannot redefine property: newKey
//ケース2:configurableをtrueに設定すると、特性を再度変更できます。
Object.defineProperty(testObj, "newKey", {
value: "こんにちは",
writable: false,
enumerable: false,
configurable: true
});
//特性を再度変更
Object.defineProperty(testObj, "newKey", {
value: "こんにちは",
writable: true,
enumerable: true,
configurable: true
});
console.log(testObj.newKey); //こんにちは
Object.definePropertyを使用してオブジェクトにプロパティを追加する場合、プロパティの特性を設定しないと、configurable、enumerable、writableの値はすべてデフォルトのfalseになります。
アクセサ記述子
プロパティの特性にアクセサ記述子を使用する場合、以下の特性プロパティを設定できます。
オブジェクトのプロパティの値を設定または取得する際に、getter/setterメソッドを提供できます。設定しない場合はundefinedになります。
- getterはプロパティの値を取得するメソッドです
- setterはプロパティの値を設定するメソッドです
注意:getterまたはsetterメソッドを使用する場合、writableとvalueのプロパティは使用できません。
var data = {};
var initialValue = 'こんにちは';
Object.defineProperty(data, "newKey", {
get: function() {
//値を取得する際に呼び出される関数
return initialValue;
},
set: function(value) {
//値を設定する際に呼び出される関数、設定された新しい値は引数valueで取得
initialValue = value;
}
});
//値を取得
console.log(data.newKey); //こんにちは
//値を設定
data.newKey = '変更された値';
console.log(data.newKey); //変更された値
getまたはsetはペアで存在する必要はなく、どちらか一方だけでも記述可能です。メソッドを設定しない場合、getとsetのデフォルト値はundefinedです。
let target = {
counter: 10
};
let baseValue = 5;
Object.defineProperty(target, 'counter', {
get: function() { // target.counterプロパティにアクセスするとgetメソッドがトリガー
/*データ操作*/
//このプロパティを取得する際に呼び出されます
baseValue *= 2;
return baseValue;
},
set(val) { // target.counterに値を設定するとsetメソッドがトリガー
//valはtarget.counterに設定する値です
}
});
console.log(target.counter < 20 && target.counter > 20); //true
/*counterは20より小さく、かつ20より大きいのは、最初にtarget.counterを判定した際にcounter=(baseValue*=2)=10となり、最初の条件を満たします。この時のbaseValueは10です。
次の判定に移ると、再度関数がトリガーされ、baseValueが20に更新され、2番目の条件も満たすため、trueとなります*/