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()
トラップに渡されるディスクリプターには制約があります。下記のプロパティのみが使用可能で、標準ではないプロパティは無視されます。
enumerable
configurable
writable
value
get
set
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> |
ブラウザーの互換性
Loading…