Object.definePropertyの理解と使い方

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に設定すると設定できません。

このプロパティの役割:

  1. プロパティをdeleteで削除できるかどうか
  2. プロパティの特性を再度設定できるかどうか
//-----------------プロパティが削除可能かどうかのテスト------------------------
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となります*/        

タグ: javascript Object.defineProperty プロパティ記述子 データバインディング getter-setter

5月31日 02:55 投稿