This article is in need of an editorial review.
This translation is incomplete. Please help translate this article from English.
ECMAScript第6版で開始し、JavaScriptはProxy
オブジェクトとReflect
オブジェクトに対してサポートが増えていて、基本的な言語操作(例えば、プロパティ検索、割り当て、列挙、関数呼び出しなど)に対してカスタム動作をインターセプトして定義することができます。これらの二つのオブジェクトの助けで、JavaScriptのメタレベルでプログラムすることができます。
Proxies
ECMAScript第6版で導入され、Proxy
オブジェクトによって、特定の操作を傍受すると、カスタム動作を実装することができます。例えば、オブジェクトのプロパティを取得します:
var handler = { get: function(target, name){ return name in target ? target[name] : 42; }}; var p = new Proxy({}, handler); p.a = 1; console.log(p.a, p.b); // 1, 42
Proxy
オブジェクトはtarget(ここではオブジェクト)とget
trapが実装されているhandlerオブジェクトを定義します。ここでは、undefinedプロパティを取得するときプロキシされているオブジェクトはundefined
を返しません。しかし、数値42をかわりに返します。
追加の例がProxy
リファレンスページにあります。
専門用語
プロキシの機能性について話すとき、次の用語が使用されます。
- handler
- トラップが含まれているプレースホルダオブジェクト。
- traps
- プロパティへのアクセスを提供するメソッド。これは、オペレーティング·システムにおけるトラップの概念に類似しています。
- target
- プロキシが仮想化するオブジェクト。これは、多くの場合、プロキシのストレージバックエンドとして使用されています。オブジェクトの非拡張性または非設定可能なプロパティについては、(変更されないままのセマンティクス)不変量は目標に照らして検証されます。
- invariants
- カスタム操作を実装するときに変更されないままのセマンティクスが不変条件と呼ばれます。ハンドラの不変条件に違反した場合、
TypeError
がスローされます。
ハンドラとトラップ
次の表は、Proxy
オブジェクトに対して利用可能なトラップをまとめたものです。詳細と例については、reference pagesをご覧ください。
Handler / trap | Interceptions | Invariants |
---|---|---|
handler.getPrototypeOf() |
Object.getPrototypeOf() Reflect.getPrototypeOf() __proto__ Object.prototype.isPrototypeOf() instanceof |
getPrototypeOf メソッドはオブジェクトかnull を返す必要があります。target が拡張可能ではない場合、Object.getPrototypeOf(proxy) メソッドはObject.getPrototypeOf(target) と同じ値を返す必要があります。 |
handler.setPrototypeOf() |
Object.setPrototypeOf() Reflect.setPrototypeOf() |
|
handler.isExtensible() |
|
|
handler.preventExtensions() |
|
|
handler.getOwnPropertyDescriptor() |
プロパティは、ターゲットオブジェクトの設定不可な独自のプロパティとして存在する場合、存在しないと報告することができません。 プロパティは、ターゲットオブジェクトの独自プロパティとして存在しターゲットオブジェクトが拡張可能ではない場合、存在しないと報告することができません。 プロパティは、ターゲットオブジェクトの独自プロパティとして存在せずターゲットオブジェクトが拡張可能ではない場合、存在すると報告することができません。 プロパティは、ターゲットオブジェクトの独自プロパティとして存在しない場合、または、ターゲットオブジェクトの設定可能な独自プロパティとして存在する場合、設定可能ではないと報告することができません。
|
|
handler.defineProperty() |
プロパティは、ターゲットオブジェクトが拡張可能ではない場合、追加されません。 プロパティは、ターゲットオブジェクトの設定不可な独自プロパティとして存在しない場合、設定不可として追加できず、設定不可に更新できません。 プロパティは、ターゲットオブジェクトの対応する設定可能なプロパティが存在する場合、設定不可ではないです。 プロパティが対応するターゲットオブジェクトプロパティを持つ場合、 strictモードでは、 |
|
handler.has() |
プロパティの照会: 継承されたプロパティの照会: |
プロパティは、ターゲットオブジェクトの設定不可の独自プロパティとして存在する場合、存在しないと報告することができません。 プロパティは、ターゲットオブジェクトの独自プロパティとして存在し、そのターゲットオブジェクトが拡張可能ではない場合、存在しないと報告することができません。 |
handler.get() |
プロパティアクセス: 継承されたプロパティアクセス: |
プロパティに対して報告される値は、ターゲットオブジェクトプロパティが書込不可で設定不可のデータプロパティである場合、対応するターゲットオブジェクトプロパティと同じ値である必要があります。 プロパティに対して報告される値は、対応するターゲットオブジェクトプロパティが、その[[Get]]属性としてundefinedを持つ設定不可のアクセスプロパティである場合undefinedである必要があります。 |
handler.set() |
プロパティの割り当て: |
対応するターゲットオブジェクトプロパティが書込不可で設定不可のデータプロパティである場合、その対応するターゲットオブジェクトプロパティと違うプロパティの値に変更できません。 対応するターゲットオブジェクトプロパティが、その[[Set]]属性として strictモードでは、 |
handler.deleteProperty() |
プロパティの削除: |
プロパティは、ターゲットオブジェクトの設定不可の独自プロパティとして存在する場合、削除されません。 |
handler.enumerate() |
プロパティ 列挙 / for...in: |
enumerate メソッドはオブジェクトを返す必要があります。 |
handler.ownKeys() |
|
|
handler.apply() |
|
handler.apply メソッドに対して全く不変量がありません。 |
handler.construct() |
|
結果は |
取消可能なProxy
Proxy.revocable()
メソッドは取消可能なProxy
オブジェクトを生成するために使用されます。これは、プロキシは、revoke
関数で取り消すことができ、プロキシを停止できることを意味します。その後、任意の操作がプロキシにつながり、TypeError
につながります。
var revocable = Proxy.revocable({}, { get: function(target, name) { return "[[" + name + "]]"; } }); var proxy = revocable.proxy; console.log(proxy.foo); // "[[foo]]" revocable.revoke(); console.log(proxy.foo); // TypeError is thrown proxy.foo = 1 // TypeError again delete proxy.foo; // still TypeError typeof proxy // "object", typeof doesn't trigger any trap
リフレクション
Reflect
はインターセプト可能なJavaScriptの操作のためのメソッドを提供するビルトインオブジェクトです。そのメソッドはproxy handlersのメソッドと同じです。Reflect
は関数オブジェクトではありません。
Reflect
はハンドラからターゲットへのデフォルト操作を転送するのに役立ちます。Reflect
はまだFirefoxでは実装されていないことに注意してください。
例えば、Reflect.has()
を用いて、関数としてin
operatorを手に入れます。:
Reflect.has(Object, "assign"); // true