UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【JavaScript】Object.defineProperty()の使い方と使い所

Object.defineProperty()の使いどころについて調べた

developer.mozilla.org

JavaScriptObject.defineProperty()は、オブジェクトのプロパティを詳細に定義・制御するためのメソッド

通常、オブジェクトにプロパティを追加すると、そのプロパティは自由に変更・削除できるが、Object.defineProperty()を使うとそれらの動作を制限できる

プロパティ記述子とは

Object.defineProperty()の第3引数には「プロパティ記述子」と呼ばれるオブジェクトを指定する

プロパティ記述子には以下のような属性がある

  • value: プロパティの値
  • writable: 値の変更を許可するか(true or false
  • enumerable: for...inObject.keys()で列挙されるか
  • configurable: 削除や再定義が可能か
  • get: プロパティ取得時に実行する関数(ゲッター)
  • set: プロパティ設定時に実行する関数(セッター)

Object.defineProperty()の基本的な使い方

オブジェクトにプロパティを追加し、値の変更を禁止する例

const obj = {};
Object.defineProperty(obj, 'property1', {
  value: 42,
  writable: false, // 変更不可
  enumerable: true, // 列挙可能
  configurable: true // 削除や再定義が可能
});
console.log(obj.property1); // 42
obj.property1 = 100;
console.log(obj.property1); // 42(writableがfalseなので変更されない)

ゲッター・セッターを使った例

getsetを使って、プロパティの値を取得・設定する際の動作を制御できる

const obj = {};
let internalValue = 0;

Object.defineProperty(obj, 'property2', {
  get() {
    return internalValue;
  },
  set(value) {
    internalValue = value * 2; // 設定した値の2倍にする
  },
  enumerable: true,
  configurable: true
});

obj.property2 = 10;
console.log(obj.property2); // 20

Object.defineProperty()の使いどころ

プロパティの値を変更不可にする

データの不変性を保証し、意図しない変更を防ぐ

プロパティの列挙を制御する

一部のプロパティだけをfor...inObject.keys()で列挙可能にする

ゲッター・セッターを使ってデータの整合性を保つ

特定の処理を挟むことで、データの変更を制御

他の活用例

変更を監視するオブジェクトを作る

Object.defineProperty()を活用すると、変更を監視するオブジェクトを作ることもできる

例えば、プロパティの変更時に特定の処理を実行するようにすれば、簡易的なデータバインディングが可能

const obj = {};
Object.defineProperty(obj, 'watchedProperty', {
  set(value) {
    console.log(`値が ${value} に変更されました`);
  }
});

obj.watchedProperty = 10; // "値が 10 に変更されました" と表示

Object.defineProperty()valueclassを指定する

Object.defineProperty()valueclassを指定することも可能

JavaScriptclassは関数(class構文で定義されたコンストラクタ関数)であり、オブジェクトとして扱えるため、valueclassを指定するとそのクラスをプロパティとして保持できる

実際の例
class MyClass {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    return `Hello, ${this.name}!`;
  }
}

const obj = {};
Object.defineProperty(obj, 'MyClassProperty', {
  value: MyClass, // クラスをプロパティとして設定
  writable: false,
  enumerable: true,
  configurable: true
});

console.log(obj.MyClassProperty); // [class MyClass]
const instance = new obj.MyClassProperty('Alice');
console.log(instance.greet()); // "Hello, Alice!"
ポイント
  1. valueclassを指定すると、そのクラス自体をオブジェクトのプロパティとして保持できる
  2. obj.MyClassProperty には MyClass というクラスが格納される
  3. new obj.MyClassProperty() を使うことで、そのクラスのインスタンスを作成できる
制限事項
  • valueにクラスを指定した場合、writable: false にすると、後からそのプロパティを別の値に変更できなくなる
  • クラスのインスタンスではなく、クラスそのもの をプロパティに格納している点に注意
  • クラスをプロパティに持つことは可能だが、通常はimport/exportrequire()を使ってモジュールとして管理するほうが一般的