JavaScript

Object.defineProperty()メソッド

 編集:2022.07.29 by T.A.

あるオブジェクトに新しいプロパティを直接定義したり、オブジェクトの既存のプロパティを変更したりして、そのオブジェクトを返します。

メモ: このメソッドは Object コンストラクターで直接呼び出すものであって、Object 型のインスタンスで呼ぶものではありません。

Object.defineProperty(obj, prop, descriptor)
obj プロパティを定義したいオブジェクト。
prop 定義または変更するプロパティの名前または Symbol
descriptor 定義または変更されるプロパティの記述子。
戻り値

渡されたオブジェクトをそのまま返します。

解説

このメソッドで、あるオブジェクトのプロパティを明示的に追加または変更することができます。代入による通常のプロパティ追加では、プロパティ列挙(for...in ループや Object.keys() メソッド)に現れ、値は変更可能で、また削除も可能なプロパティが生成されます。このメソッドでは、これらの詳細事項を既定値から変えることが可能です。既定では、Object.defineProperty() を使って追加された値は不変になります。

プロパティの記述子は、データ記述子とアクセサー記述子の二つに分かれます。データ記述子は値を持つプロパティで、その値は書き換え可能にも不可能にもできます。アクセサー記述子は、関数のゲッターとセッターの組で表されるプロパティです。記述子はこれら二種類のどちらかでなければならず、両方になることはできません。

どちらの形でも記述子はオブジェクトで表現します。共通して以下のキーを持つことができます(既定値は Object.defineProperty() を使ってプロパティを定義する場合)。

configurable true である場合のみ、この種の記述子を変更することや、対応するオブジェクトからプロパティを削除することができます。

既定値は false です。

enumerable true である場合のみ、このプロパティは対応するオブジェクトでのプロパティ列挙に現れます。

既定値は false です。

データ記述子の場合はオプションとして次のキーを持つことができます:

value プロパティに関連づけられた値です。有効な JavaScript の値(number、object、function など)である必要があります。

既定値は undefined です。

writable true である場合のみ、プロパティに関連づけられた値は代入演算子で変更することができます。

既定値は false です。

アクセサー記述子の場合はオプションとして次のキーを持つことができます:

get プロパティのゲッターとなる関数で、ゲッターを設けない場合は undefined です。プロパティにアクセスするとこの関数が引数なしでコールされます。この関数内で this はアクセスしようとしたプロパティを持つオブジェクトになります(プロパティを定義するために作成した記述子オブジェクトではありません)。戻り値はこのプロパティの値として使われます。

既定値は undefined です。

set プロパティのセッターとなる関数で、セッターがない場合は undefined です。プロパティに値が割り当てられたとき、その値を引数としてこの関数がコールされます。この関数内で this は割り当てようとしたプロパティを持つオブジェクトになります。

既定値は undefined です。

記述子に value、writable、get、set のいずれのキーもない場合、データ記述子として扱われます。記述子に value または writable と、get または set のキーの両方がある場合は、例外が投げられます。

これらのキーは必ずしも記述子が直接所有しているとは限らないことに留意してください。継承されたプロパティも同様です。これらの既定値が存在することを保証するには、先行して Object.prototype を freeze しておくか、すべてのオプションを明示的に指定するか、Object.create(null) で null に設定するかします。

¶省く

バイナリー フラグを使って Object.defineProperty() を利用したい場合は「追加の例」× を見てください。

プロパティの生成:

オブジェクトに指定されたプロパティが存在しないとき、Object.defineProperty() は指定された形で新たなプロパティを生成します。記述子のキーは省略することができ、そのようなキーには既定値が適用されます。

var o = {};	// 新しいオブジェクトの生成

// データ記述子により、defineProperty を用いて
// オブジェクトプロパティを追加する例
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});	// o オブジェクトに 'a' プロパティが存在するようになり、その値は 37 となります

// アクセサー記述子により、defineProperty を用いて
// オブジェクトプロパティを追加する例
var bValue = 38;
Object.defineProperty(o, 'b', {
  // メソッド名ショートハンドを利用しています(ES2015 の機能)。
  // 次のように書いているのと同じことです:
  // get: function() { return bValue; },
  // set: function(newValue) { bValue = newValue; },
  get() { return bValue; },
  set(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});
D=o.b;	//=38
// o オブジェクトに 'b' プロパティが存在するようになり、
// その値は 38 となります
// o.b は再定義されない限り、その値は常に bValue と同じです。

// (訳注:データとアクセサーを)両方を混在させることはできません:
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get() { return 0xdeadbeef; }
});
// TypeError が発生します。value はデータ記述子にのみ、
// get はアクセサー記述子にのみ存在していなければなりません。

¶省く


テスト