handler.defineProperty()
Baseline
Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2016年9月.
handler.defineProperty() は、オブジェクトの [[DefineOwnProperty]] 内部メソッドに対するトラップです。Object.defineProperty() などの操作で使用されます。
試してみましょう
const handler = {
defineProperty(target, key, descriptor) {
invariant(key, "define");
return true;
},
};
function invariant(key, action) {
if (key[0] === "_") {
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
}
}
const monster = {};
const proxy = new Proxy(monster, handler);
console.log((proxy._secret = "easily scared"));
// 予想される結果: Error: Invalid attempt to define private "_secret" property
構文
new Proxy(target, {
defineProperty(target, property, descriptor) {
}
})
引数
次の引数が defineProperty() メソッドに渡されます。 this はハンドラーにバインドされます。
target-
ターゲットオブジェクトです。
property-
説明を受け取るプロパティの名前または
Symbolです。 descriptor-
定義や変更されるプロパティに対するディスクリプターです。
返値
defineProperty() メソッドはプロパティが正しく定義されたかどうかを表す論理値を返す必要があります。それ以外の値は論理値に強制変換されます。
多くの操作(Object.defineProperty() および Object.defineProperties() を含む)は、[[DefineOwnProperty]] 内部メソッドが false を返す場合、TypeError が発生します。
解説
>介入
このトラップは下記の操作に介入できます。
他にも、[[DefineOwnProperty]] 内部メソッドを呼び出すあらゆる操作に介入できます。
不変条件
プロキシーの [[DefineOwnProperty]] 内部メソッドは、ハンドラーの定義が以下の不変条件のいずれかに違反する場合、TypeError が発生します。
- プロパティを追加することはできません。対象オブジェクトが拡張可能でない場合です。つまり、
Reflect.isExtensible()がtarget上のプロパティに対してfalseを返し、Reflect.getOwnPropertyDescriptor()がtarget上のプロパティに対してundefinedを返す場合、トラップは偽値を返す必要があります。 - プロパティは、ターゲットオブジェクトに対応する構成不可な自身のプロパティが存在しない限り、構成不可にできません。つまり、
Reflect.getOwnPropertyDescriptor()がtarget上のプロパティに対してundefinedまたはconfigurable: trueを返す場合、かつdescriptor.configurableがfalseである場合、トラップは偽値を返す必要があります。 - 構成不可プロパティは、ターゲットオブジェクトに該当する構成不可かつ非書き込み可能の固有プロパティが存在する場合を除き、非書き込み可能ではありません。つまり、
Reflect.getOwnPropertyDescriptor()がtarget上のプロパティに対してconfigurable: false, writable: trueを返し、descriptor.writableがfalseである場合、トラップは偽値を返す必要があります。 - プロパティが対象オブジェクトに対応するプロパティを保有する場合、対象オブジェクトのプロパティの記述子は
descriptorと互換性がある必要があります。つまり、targetを通常のオブジェクトと仮定し、Object.defineProperty(target, property, descriptor)がエラーを発生すると仮定した場合、トラップは偽値を返す必要があります。Object.defineProperty()の参照には詳細な情報が含まれていますが、簡単に言うと、ターゲットプロパティが構成不可の場合、以下の条件が満たされる必要があります。configurable、enumerable、get、setは変更できません- プロパティはデータとアクセサーの間で切り替えることができません
writable属性はtrueからfalseに変更できますvalue属性はwritableがtrueの場合にのみ変更できます
例
>defineProperty のトラップ
次のコードは Object.defineProperty() をトラップします。
const p = new Proxy(
{},
{
defineProperty(target, prop, descriptor) {
console.log(`called: ${prop}`);
return true;
},
},
);
const desc = { configurable: true, enumerable: true, value: 10 };
Object.defineProperty(p, "a", desc); // "called: a"
Object.defineProperty() または Reflect.defineProperty() を呼び出した時、 defineProperty() トラップに渡されるディスクリプターには制約があります。下記のプロパティのみが使用可能で、標準ではないプロパティは無視されます。
enumerableconfigurablewritablevaluegetset
const p = new Proxy(
{},
{
defineProperty(target, prop, descriptor) {
console.log(descriptor);
return Reflect.defineProperty(target, prop, descriptor);
},
},
);
Object.defineProperty(p, "name", {
value: "proxy",
type: "custom",
}); // { value: 'proxy' }
仕様書
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-proxy-object-internal-methods-and-internal-slots-defineownproperty-p-desc> |