メタプログラミングとは、開発者が「言語自体をプログラムする」ことです。一般に、プログラミング言語は、開発者が言語自体の特定の機能を操作できるように、いくつかの API を公開します。
ES6 以降、プロキシ機能とリフレクト機能が追加され、メタ プログラミング (メタ プログラミング) 機能が拡張され、基本的な言語操作動作 (属性の検索、割り当て、列挙、関数呼び出しなど) のインターセプトとカスタマイズが可能になりました。 。
Proxy (プロキシ)
プロキシは、オブジェクトのネイティブ動作を「プロキシ」し、カスタム動作の実行に置き換えることができる新機能です。
プロキシは、ターゲット オブジェクトの前に「インターセプト」層を設定するものとして理解できます。オブジェクトへの外部アクセスは、まずこのインターセプト層を通過する必要があるため、外部アクセスをフィルタリングして書き換えるメカニズムを提供します。プロキシという言葉の本来の意味は代理店であり、ここでは「代理人」と訳せます。
Proxy オブジェクトは、基本的な操作 (プロパティの検索、割り当て、列挙、メソッド呼び出しなど) のユーザー定義の動作を定義するために使用されます。
プロキシ オブジェクトを作成します:
target: ターゲット オブジェクト。配列、関数、または別のプロキシ オブジェクトなど、任意のタイプのオブジェクトを指定できます。
handlert: 生成されたプロキシ オブジェクトのさまざまな動作を制御するためのプロキシ メソッドのセットを含むハンドラー オブジェクト。
プロキシ オブジェクトのメソッド:
Proxy.revocable(target, handler): 取り消し可能なプロキシ オブジェクトの作成に使用されます。
ハンドラー オブジェクトには合計 14 のプロキシ メソッドがあります:
handler.getPrototypeOf(): この操作は、Object.getPrototypeOf(proxy) の実行時など、プロキシ オブジェクトのプロトタイプを読み取るときにトリガーされます。
handler.setPrototypeOf(): この操作は、Object.setPrototypeOf(proxy, null) を実行するときなど、プロキシ オブジェクトのプロトタイプを設定するときにトリガーされます。
handler.isExtensible(): この操作は、Object.isExtensible(proxy) の実行時など、プロキシ オブジェクトが拡張可能かどうかを判断するときにトリガーされます。
handler.preventExtensions(): Object.preventExtensions(proxy) を実行するときなど、プロキシ オブジェクトを拡張不可能にするときにトリガーされます。
handler.getOwnPropertyDescriptor(): この操作は、Object.getOwnPropertyDescriptor(proxy, “foo”) を実行するときなど、プロキシ オブジェクトのプロパティのプロパティの説明を取得するときにトリガーされます。
handler.defineProperty(): この操作は、Object.defineProperty(proxy, “foo”, {}) を実行するときなど、プロキシ オブジェクトのプロパティのプロパティの説明を定義するときにトリガーされます。
handler.has(): この操作は、プロキシで「foo」を実行するときなど、プロキシ オブジェクトが特定の属性を持つかどうかを判断するときにトリガーされます。
handler.get(): この操作は、proxy.foo の実行時など、プロキシ オブジェクトの特定のプロパティを読み取るときにトリガーされます。
handler.set(): この操作は、proxy.foo = 1 を実行するときなど、プロキシ オブジェクトの特定の属性に値を割り当てるときにトリガーされます。
handler.deleteProperty(): この操作は、delete proxy.foo が実行されたときなど、プロキシ オブジェクトのプロパティが削除されたときにトリガーされます。
handler.enumerate(): この操作は、for(i in proxy){} を実行するときなど、プロキシ オブジェクトのプロパティを走査するときにトリガーされます。
handler.ownKeys(): この操作は、Object.getOwnPropertyNames(proxy) の実行時など、プロキシ オブジェクトのすべてのプロパティ キーが取得されたときにトリガーされます。
handler.apply(): この操作は、proxy() の実行時など、ターゲット オブジェクトが関数であるプロキシ オブジェクトが呼び出されたときにトリガーされます。
handler.construct(): この操作は、new proxy() の実行時など、ターゲット オブジェクトがコンストラクターであるプロキシ オブジェクトのインスタンスを構築するときにトリガーされます。
属性値の読み取り操作のインターセプト:
上記のコードでは、Proxy (プロキシ) オブジェクトはターゲットとハンドルを定義し、ハンドルは get Capture メソッドを実装します。このメソッドにより、プロキシされたオブジェクトは、未定義のプロパティに対して未定義を返さなくなり、数値 42 を返します。
属性値の割り当て操作をインターセプトします:
上記のコードでは、リッスンしているオブジェクトの属性が変更されると、このハンドラー関数が設定されます。 Call となり、同時にパラメータを通じてどの属性がどのような値に変更されたのかを知ることができます。
複数の操作をインターセプトするように同じインターセプター関数を設定できます。
Proxy.revocable メソッドは、プロキシ オブジェクトが取り消されると、取り消し可能なプロキシ オブジェクトを作成するために使用されます。ほぼ完全に使用できず、プロキシ可能な操作を実行すると TypeError 例外がスローされます。
Reflect (リフレクション)
ES6 で導入された Reflect は、オブジェクトのネイティブ動作を直接操作できるようにするもう 1 つのメタプログラミング機能です。 Reflect の制御可能な動作と Proxy のプロキシの間には 1 対 1 の対応関係があるため、Reflect を使用して Proxy のカスタム メソッドでネイティブ動作を呼び出すことが簡単になります。
Reflection (リフレクション) は、プログラムの実行中にプログラム自体の特性を動的に表示できる貴重な言語機能です。
Reflect オブジェクトには 14 の静的メソッドがあり、それらの名前はたまたま 14 のプロキシ プロセッサ メソッドの名前と同じです。機能は似ていますが、微妙な違いがあります。
Reflect.apply(): 関数を呼び出し、呼び出しパラメーターとして配列を渡します。 Function.prototype.apply() に似ています。
Reflect.construct(): コンストラクターで新しい操作を実行することは、new target(...args) を実行することと同じです。
Reflect.defineProperty(): Object.defineProperty() に似ています。
Reflect.deleteProperty(): オブジェクトのプロパティを削除することは、delete target[name] を実行することと同じです。
Reflect.enumerate(): このメソッドは、すべての列挙可能な独自の文字列プロパティとターゲット オブジェクトの継承された文字列プロパティを含むイテレータを返します。for...in 操作が通過するのはこれらのプロパティです。
Reflect.get(): target[name] と同様に、オブジェクトの属性の値を取得します。
Reflect.getOwnPropertyDescriptor(): Object.getOwnPropertyDescriptor() に似ています。
Reflect.getPrototypeOf(): Object.getPrototypeOf() に似ています。
Reflect.has(): オブジェクトが特定の属性を持っているかどうかを判断します。これは in 演算子と同じ機能を持ちます。
Reflect.isExtensible(): Object.isExtensible() に似ています。
Reflect.ownKeys(): すべての独自のプロパティ (継承されたプロパティを除く) を含む配列を返します。
Reflect.preventExtensions(): Object.preventExtensions() に似ています。
Reflect.set(): target[name] = val と同様に、オブジェクトの属性の値を設定します。
Reflect.setPrototypeOf(): Object.setPrototypeOf() に似ています。
上記のコードでは、Proxy メソッドがターゲット オブジェクトの属性割り当て動作をインターセプトし、Reflect.set メソッドを使用してオブジェクトの属性に値を割り当てます。
Reflect を使用する理由:
明らかに言語の内部にある Object オブジェクトのメソッド (Object.defineProperty など) を Reflect オブジェクトに追加します。この段階では、一部のメソッドは Object オブジェクトと Reflect オブジェクトの両方にデプロイされますが、将来の新しいメソッドは Reflect オブジェクトにのみデプロイされます。
一部の Object メソッドの戻り結果を変更して、より合理的なものにします。たとえば、Object.defineProperty(obj, name, desc) はプロパティを定義できない場合にエラーをスローしますが、Reflect.defineProperty(obj, name, desc) は false を返します。
オブジェクトの操作を機能的な動作に変換します。 name in obj や delete obj[name] など、一部のオブジェクト操作は必須ですが、Reflect.has(obj, name) と Reflect.deleteProperty(obj, name) はそれらを関数的な動作に変換します。
Reflect オブジェクトのメソッドは Proxy オブジェクトのメソッドと 1 対 1 に対応しており、Proxy オブジェクトのメソッドである限り、対応するメソッドは Reflect オブジェクト上で見つけることができます。これにより、Proxy オブジェクトは対応する Reflect メソッドを簡単に呼び出してデフォルトの動作を完了し、動作を変更するための基礎として機能できるようになります。言い換えれば、Proxy がデフォルトの動作をどのように変更しても、Reflect では常にデフォルトの動作を取得できます。
上記のコードでは、Proxy オブジェクトの各インターセプト操作 (get、delete、has) が対応する Reflect メソッドを内部的に呼び出して、ネイティブの動作が正常に実行できることを確認します。追加された作業は、操作ごとに 1 行のログを出力することです。 Reflect オブジェクトを使用すると、多くの操作が読みやすくなります。
以上がES6 新機能開発 WeChat アプレット (6)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。