【JS応用|豆知識】オブジェクトの挙動を自在に操る!JavaScript「プロパティ記述子」入門

導入

JavaScriptでオブジェクトを扱う際、通常はプロパティを代入したり削除したりすることは自由です。しかし、大規模なアプリケーション開発では「このプロパティは書き換えてほしくない」「列挙(ループ)に含まれないようにしたい」といった制約が必要になる場面があります。そんな時、オブジェクトのプロパティの「振る舞い」を細かく制御できるのが「プロパティ記述子(Property Descriptor)」です。

基礎知識

プロパティ記述子とは、オブジェクトの各プロパティに対して設定できる「属性」の集まりです。主に以下の2種類が存在します。

データ記述子:値(value)を持ち、書き込み可能か、削除可能かなどを制御します。
アクセサ記述子:値の代わりにゲッター(get)とセッター(set)関数を持ち、値へのアクセスをフックします。

これらの設定は、Object.defineProperty() メソッドを使用することで個別に制御可能です。

実装/解決策

プロパティ記述子を活用するには、Object.defineProperty(対象オブジェクト, プロパティ名, 記述子オブジェクト) を使用します。主なフラグは以下の通りです。

・value: プロパティの値
・writable: trueにすると値の書き換えが可能(デフォルト: false)
・enumerable: trueにするとObject.keys()やfor…inでの列挙が可能(デフォルト: false)
・configurable: trueにするとプロパティの削除や記述子の再設定が可能(デフォルト: false)

サンプルプログラム

以下のコードでは、書き換え不可で列挙もされない「定数のようなプロパティ」を定義しています。

const user = {};

// プロパティを定義
Object.defineProperty(user, 'id', {
  value: 101,
  writable: false,     // 書き換え不可
  enumerable: false,   // ループで表示されない
  configurable: false  // 削除や再定義不可
});

// 値の書き換えを試みる(エラーにはならないが反映されない)
user.id = 999;
console.log(user.id); // 101 が出力される

// 列挙を試みる
console.log(Object.keys(user)); // [] プロパティは隠蔽されている

// 削除を試みる
delete user.id;
console.log(user.id); // 101 削除もできない

応用・注意点

現場での活用として、特によく使われるのが「イミュータブル(不変)なオブジェクトの作成」です。Object.freeze() は内部的に全てのプロパティの configurable と writable を false に設定しています。

注意点:
記述子を明示的に指定しない場合、Object.defineProperty() で作成したプロパティは、デフォルトですべて「false」になります(通常の代入操作とはデフォルト値が異なる点に注意してください)。また、strictモードを使用している場合、書き込み不可のプロパティを書き換えようとすると TypeError がスローされるため、意図しないバグを早期に発見しやすくなります。積極的に活用して、堅牢なデータ構造を作り上げましょう。

タイトルとURLをコピーしました