From 994256da315f0ce271e282b16c488dcb7d8ae7a1 Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Fri, 21 May 2021 00:33:49 +0900 Subject: Web/JavaScript/Guide/Meta_programming を更新 (#800) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2021/04/18 時点の英語版に同期 - 原語併記マクロを削除 --- .../javascript/guide/meta_programming/index.html | 213 +++++++++++---------- 1 file changed, 117 insertions(+), 96 deletions(-) diff --git a/files/ja/web/javascript/guide/meta_programming/index.html b/files/ja/web/javascript/guide/meta_programming/index.html index c0b3b18129..253ed92922 100644 --- a/files/ja/web/javascript/guide/meta_programming/index.html +++ b/files/ja/web/javascript/guide/meta_programming/index.html @@ -7,22 +7,22 @@ tags: - JavaScript - Proxy - Reflect - - 'l10n:priority' + - l10n:priority translation_of: Web/JavaScript/Guide/Meta_programming --- -
{{jsSidebar("JavaScript Guide")}} {{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}
+
{{jsSidebar("JavaScript Guide")}}{{PreviousNext("Web/JavaScript/Guide/Iterators_and_Generators", "Web/JavaScript/Guide/Modules")}}
-

ECMAScript 2015 から、JavaScript には {{jsxref("Proxy")}} オブジェクトと {{jsxref("Reflect")}} オブジェクトがサポートされました。これらは基本的な言語操作(例えば、プロパティ検索、代入、列挙、関数呼び出しなど)に割り込み、動作をカスタマイズできます。この 2 つのオブジェクトのおかげで、JavaScript でメタレベルのプログラミングが行えます。

+

ECMAScript 2015 から、JavaScript には {{jsxref("Proxy")}} オブジェクトと {{jsxref("Reflect")}} オブジェクトがサポートされました。これらは基本的な言語操作 (例えば、プロパティ参照、代入、列挙、関数呼び出しなど) に割り込み、動作をカスタマイズすることができます。この 2 つのオブジェクトのおかげで、JavaScript でメタレベルのプログラミングが行えます。

-

Proxy

+

プロキシー

-

ECMAScript 6 で導入された {{jsxref("Proxy")}} オブジェクトによって、特定の操作に割り込んで動作をカスタマイズできます。

+

ECMAScript 6 で導入された {{jsxref("Proxy")}} オブジェクトによって、特定の操作に割り込んで動作をカスタマイズすることができます。

-

例えば、オブジェクトのプロパティを取得してみましょう :

+

例えば、オブジェクトのプロパティを取得してみましょう。

-
let handler = {
+
let handler = {
   get: function(target, name) {
-    return name in target? target[name] : 42
+    return name in target ? target[name] : 42
   }
 }
 
@@ -31,141 +31,155 @@ p.a = 1
 console.log(p.a, p.b) // 1, 42
 
-

この Proxy オブジェクトは target(ここでは空オブジェクト)と get トラップが実装された handler オブジェクトを定義しています。ここで、プロキシとなったオブジェクトは未定義のプロパティを取得しようとした時 undefined を返さず、代わりに数値 42 を返します。

+

この Proxy オブジェクトは target (ここでは空オブジェクト) と handler オブジェクトを定義し、その中に get トラップが実装されています。ここで、プロキシーとなったオブジェクトは未定義のプロパティを取得しようとした時に undefined を返さず、代わりに数値 42 を返します。

-

さらなる使用例がリファレンスの「{{jsxref("Proxy")}}」ページにあります。

+

それ以外の例は {{jsxref("Proxy")}} のリファレンスページを参照してください。

-

用語集

+

用語集

-

プロキシの機能について話題にする際は、次の用語が使用されます。

+

プロキシーの機能について話題にする際は、次の用語が使用されます。

-
{{jsxref("Global_Objects/Proxy/handler","ハンドラ","","true")}} (handler)
+
{{jsxref("Global_Objects/Proxy/Proxy","ハンドラー","","true")}} (handler)
トラップを入れるためのプレースホルダ用オブジェクト。
-
{{原語併記("トラップ","trap")}}
-
プロパティへのアクセスを提供するメソッド。オペレーティングシステムにおけるトラップの概念と同じようなものです。
-
{{原語併記("ターゲット","target")}}
-
プロキシが仮想化するオブジェクト。これはプロキシのストレージバックエンドとしてしばしば使われます。拡張・設定可能でないプロパティを持つオブジェクトに関する不変条件(変更されないセマンティック、つまりオブジェクトの意味情報)は、このターゲットに対して検証されます。
-
{{原語併記("不変条件","invariant")}}
-
カスタマイズした動作を実装する際、変更されないセマンティックを不変条件と呼びます。ハンドラの不変条件に違反した場合、{{jsxref("TypeError")}} が発生します。
+
トラップ (trap)
+
プロパティへのアクセスを提供するメソッドです。 (オペレーティングシステムにおけるトラップの概念と同じようなものです。)
+
ターゲット (target)
+
プロキシーが仮想化するオブジェクトです。多くの場合、プロキシーのストレージバックエンドとして使用されます。拡張や設定できないオブジェクトのプロパティの不変条件 (変更されない意味) がターゲットに対して検証されます。
+
不変条件 (invariant)
+
独自の操作を実装した際に変更されない意味を不変条件と呼びます。ハンドラーの不変条件に違反した場合、 {{jsxref("TypeError")}} が発生します。
-

ハンドラとトラップ

+

ハンドラーとトラップ

-

次の表は、Proxy オブジェクトに対して利用可能なトラップをまとめたものです。詳細と例についてはリファレンスのハンドラについてのページをご覧ください。

+

次の表は、 Proxy オブジェクトに対して利用可能なトラップをまとめたものです。詳細な説明と例については、リファレンスページを参照してください。

- + - + - + - + - + - + - + - + - + - - + + - - + + - - + + - - - + + + - - + + - + - + - + - + @@ -220,13 +241,13 @@ console.log(p.a, p.b) // 1, 42
ハンドラ / トラップハンドラー / トラップ 割り込みされる処理 不変条件
{{jsxref("Global_Objects/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}}{{jsxref("Global_Objects/Proxy/Proxy/getPrototypeOf", "handler.getPrototypeOf()")}} {{jsxref("Object.getPrototypeOf()")}}
{{jsxref("Reflect.getPrototypeOf()")}}
{{jsxref("Object/proto", "__proto__")}}
{{jsxref("Object.prototype.isPrototypeOf()")}}
{{jsxref("Operators/instanceof", "instanceof")}}
-
    +
    • getPrototypeOf メソッドはオブジェクトか null を返す必要があります。
    • -
    • target が拡張不可の場合、Object.getPrototypeOf(proxy) メソッドは Object.getPrototypeOf(target) と同じ値を返す必要があります。
    • +
    • target が拡張できない場合、Object.getPrototypeOf(proxy) メソッドは Object.getPrototypeOf(target) と同じ値を返す必要があります。
{{jsxref("Global_Objects/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}}{{jsxref("Global_Objects/Proxy/Proxy/setPrototypeOf", "handler.setPrototypeOf()")}} {{jsxref("Object.setPrototypeOf()")}}
{{jsxref("Reflect.setPrototypeOf()")}}
target が拡張不可の場合、prototype パラメータは Object.getPrototypeOf(target) と同じ値である必要があります。target が拡張できない場合、prototype パラメータは Object.getPrototypeOf(target) と同じ値である必要があります。
{{jsxref("Global_Objects/Proxy/handler/isExtensible", "handler.isExtensible()")}}{{jsxref("Global_Objects/Proxy/Proxy/isExtensible", "handler.isExtensible()")}} {{jsxref("Object.isExtensible()")}}
{{jsxref("Reflect.isExtensible()")}}
Object.isExtensible(proxy)Object.isExtensible(target) と同じ値を返す必要があります。Object.isExtensible(proxy)Object.isExtensible(target) と同じ値を返す必要があります。
{{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}}{{jsxref("Global_Objects/Proxy/Proxy/preventExtensions", "handler.preventExtensions()")}} {{jsxref("Object.preventExtensions()")}}
{{jsxref("Reflect.preventExtensions()")}}
-

Object.isExtensible(proxy)false の場合のみ、Object.preventExtensions(proxy)true を返します。

+

Object.isExtensible(proxy)false の場合のみ、Object.preventExtensions(proxy)true を返します。

{{jsxref("Global_Objects/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}}{{jsxref("Global_Objects/Proxy/Proxy/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}} {{jsxref("Object.getOwnPropertyDescriptor()")}}
{{jsxref("Reflect.getOwnPropertyDescriptor()")}}
-
    +
    • getOwnPropertyDescriptor はオブジェクトか undefined のいずれかを返す必要があります。
    • ターゲットオブジェクトに設定不可の所有プロパティとして存在する場合、そのプロパティについて存在しないと報告することはできません。
    • 拡張不可のターゲットオブジェクトに所有プロパティとして存在する場合、そのプロパティについて存在しないと報告することはできません。
    • 拡張不可のターゲットオブジェクトに所有プロパティとして存在しない場合、そのプロパティについて存在すると報告することはできません。
    • ターゲットオブジェクトに所有プロパティとして存在しない場合、あるいはターゲットオブジェクトに設定可能な所有プロパティとして存在する場合、そのプロパティについて設定不可と報告することはできません。
    • -
    • Object.getOwnPropertyDescriptor(target) の結果は Object.defineProperty を使用してターゲットオブジェクトに適用され、この時に例外は発生しません。
    • +
    • Object.getOwnPropertyDescriptor(target) の結果は Object.defineProperty を使用してターゲットオブジェクトに適用され、この時に例外は発生しません。
{{jsxref("Global_Objects/Proxy/handler/defineProperty", "handler.defineProperty()")}}{{jsxref("Global_Objects/Proxy/Proxy/defineProperty", "handler.defineProperty()")}} {{jsxref("Object.defineProperty()")}}
{{jsxref("Reflect.defineProperty()")}}
-
    +
    • ターゲットオブジェクトが拡張可能ではない場合、プロパティは追加できません。
    • ターゲットオブジェクトに設定不可の所有プロパティとして存在しない場合、そのプロパティを追加したり、また設定不可に更新することはできません。
    • ターゲットオブジェクトに対応する設定可能なプロパティとして存在する場合、そのプロパティを設定不可としてもかまいません。
    • -
    • プロパティが対応するターゲットオブジェクトプロパティを持つ場合、Object.defineProperty(target, prop, descriptor) は例外を発生しません。
    • -
    • strict モードでは、defineProperty ハンドラからの戻り値が false の場合、{{jsxref("TypeError")}} 例外が発生します。
    • +
    • プロパティが対応するターゲットオブジェクトプロパティを持つ場合、Object.defineProperty(target, prop, descriptor) は例外を発生しません。
    • +
    • strict モードでは、defineProperty ハンドラーからの返値が false の場合、{{jsxref("TypeError")}} 例外が発生します。
{{jsxref("Global_Objects/Proxy/handler/has", "handler.has()")}}プロパティの照会 :
- foo in proxy
- 継承されたプロパティの照会 :
- foo in Object.create(proxy)
- {{jsxref("Reflect.has()")}}
{{jsxref("Global_Objects/Proxy/Proxy/has", "handler.has()")}} -
    +
    +
    プロパティの照会
    +
    foo in proxy
    +
    継承されたプロパティの照会
    +
    foo in Object.create(proxy)
    + {{jsxref("Reflect.has()")}}
    +
    +
+
  • ターゲットオブジェクトに設定不可の所有プロパティとして存在する場合、そのプロパティについて存在しないと報告することはできません。
  • ターゲットオブジェクトの所有プロパティとして存在し、そのターゲットオブジェクトが拡張可能ではない場合、そのプロパティについて存在しないと報告することはできません。
{{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}}プロパティへのアクセス :
- proxy[foo]and proxy.bar
- 継承されたプロパティアクセス :
- Object.create(proxy)[foo]
- {{jsxref("Reflect.get()")}}
{{jsxref("Global_Objects/Proxy/Proxy/get", "handler.get()")}} +
+
プロパティへのアクセス
+
proxy[foo]
+ proxy.bar
+
継承されたプロパティへのアクセス
+
Object.create(proxy)[foo]
+ {{jsxref("Reflect.get()")}}
+
+
-
    +
    • ターゲットオブジェクトプロパティが書込不可、設定不可のデータプロパティである場合、プロパティに対して報告する値は対応するプロパティと同じ値である必要があります。
    • 対応するターゲットオブジェクトプロパティが、Get 属性に undefined を持つ設定不可のアクセサプロパティである場合、プロパティに対して報告される値を undefined とする必要があります。
{{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}}プロパティへの代入 :
- proxy[foo] = bar, proxy.foo = bar
- 継承されたプロパティの割り当て :
- Object.create(proxy)[foo] = bar
- {{jsxref("Reflect.set()")}}
{{jsxref("Global_Objects/Proxy/Proxy/set", "handler.set()")}} +
+
プロパティへの代入
+
proxy[foo] = bar
+ proxy.foo = bar
+
継承されたプロパティへの代入
+
Object.create(proxy)[foo] = bar
+ {{jsxref("Reflect.set()")}}
+
+
-
    +
    • 対応するターゲットオブジェクトのプロパティが書込不可、設定不可のデータプロパティである場合、そのプロパティとは違うプロパティ値に変更することはできません。
    • 対応するターゲットオブジェクトプロパティが、Set 属性に undefined を持つ設定不可のアクセサプロパティである場合、プロパティの値を設定することはできません。
    • -
    • strict モードでは、set ハンドラからの戻り値が false の場合、{{jsxref("TypeError")}} 例外が発生します。 +
    • strict モードでは、 false という返値が set ハンドラーから返された場合、{{jsxref("TypeError")}} 例外が発生します。
    • @@ -173,46 +187,53 @@ console.log(p.a, p.b) // 1, 42
{{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}}プロパティの削除 :
- delete proxy[foo], delete proxy.foo
- {{jsxref("Reflect.deleteProperty()")}}
ターゲットオブジェクトに設定不可の所有プロパティとして存在する場合、削除することはできません。{{jsxref("Global_Objects/Proxy/Proxy/deleteProperty", "handler.deleteProperty()")}} +
+
プロパティの削除
+
delete proxy[foo]
+ delete proxy.foo
+ {{jsxref("Reflect.deleteProperty()")}}
+
+
target に構成不可の所有プロパティとして存在する場合、削除することはできません。
{{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}}プロパティの列挙 / for...in :
- for (var name in proxy) {...}
- {{jsxref("Reflect.enumerate()")}}
{{jsxref("Global_Objects/Proxy/enumerate", "handler.enumerate()")}} +
+
プロパティの列挙 / for...in:
+
for (let name in proxy) {...}
+ {{jsxref("Reflect.enumerate()")}}
+
+
enumerate メソッドはオブジェクトを返す必要があります。
{{jsxref("Global_Objects/Proxy/handler/ownKeys", "handler.ownKeys()")}}{{jsxref("Global_Objects/Proxy/Proxy/ownKeys", "handler.ownKeys()")}} {{jsxref("Object.getOwnPropertyNames()")}}
{{jsxref("Object.getOwnPropertySymbols()")}}
{{jsxref("Object.keys()")}}
{{jsxref("Reflect.ownKeys()")}}
-
    +
    • ownKeys の結果はリストとなります。
    • 出力リストの要素の型は {{jsxref("String")}} か {{jsxref("Symbol")}} のどちらかとなります。
    • -
    • 出力リストはターゲットオブジェクト中にあるすべての設定不可な所有プロパティのキーを含める必要があります。
    • -
    • ターゲットオブジェクトが拡張不可の場合、出力リストはターゲットオブジェクト中の所有プロパティのキーをすべて含める必要があり、他の値は含まれません。 -
        -
      +
    • 出力リストは target のすべての設定不可の所有プロパティのキーを含める必要があります。
    • +
    • ターゲットオブジェクトが拡張できない場合、出力リストはターゲットオブジェクト中の所有プロパティのキーをすべて含める必要があり、他の値は含まれません。
{{jsxref("Global_Objects/Proxy/handler/apply", "handler.apply()")}}{{jsxref("Global_Objects/Proxy/Proxy/apply", "handler.apply()")}} proxy(..args)
{{jsxref("Function.prototype.apply()")}} and {{jsxref("Function.prototype.call()")}}
{{jsxref("Reflect.apply()")}}
handler.apply メソッドに対する不変条件はありません。handler.apply メソッドに対する不変条件はありません。
{{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}}{{jsxref("Global_Objects/Proxy/Proxy/construct", "handler.construct()")}} new proxy(...args)
{{jsxref("Reflect.construct()")}}
出力結果は Object とする必要があります。
-

取り消し可能 Proxy

+

取り消し可能 Proxy

-

{{jsxref("Proxy.revocable()")}} メソッドは取り消し可能な Proxy オブジェクトの生成に使用されます。これにより、プロキシを revoke 関数で取り消し、プロキシの機能を停止することができます。

+

{{jsxref("Proxy.revocable()")}} メソッドは取り消し可能な Proxy オブジェクトの生成に使用されます。これにより、プロキシーを revoke 関数で取り消し、プロキシーの機能を停止することができます。

-

その後はプロキシを通じたいかなる操作も {{jsxref("TypeError")}} になります。

+

その後はプロキシーを通じたいかなる操作も {{jsxref("TypeError")}} になります。

-
let revocable = Proxy.revocable({}, {
+
let revocable = Proxy.revocable({}, {
   get: function(target, name) {
     return '[[' + name + ']]'
   }
@@ -242,29 +263,29 @@ delete proxy.foo        // TypeError がここでも発生
 typeof proxy            // "object" が返され, typeof はどんなトラップも引き起こさない
 
-

リフレクション

+

リフレクション

-

{{jsxref("Reflect")}} は JavaScript で割り込み操作を行うメソッドを提供するビルトインオブジェクトです。そのメソッドは {{jsxref("Global_Objects/Proxy/handler","Proxy ハンドラ","","true")}}のメソッドと同じです。

+

{{jsxref("Reflect")}} は JavaScript で割り込み操作を行うメソッドを提供する組み込みオブジェクトです。そのメソッドは{{jsxref("Global_Objects/Proxy/Proxy","Proxy ハンドラー","","true")}}のメソッドと同じです。

Reflect は関数オブジェクトではありません。

-

Reflect はハンドラからターゲットへのデフォルト操作を転送するのに役立ちます。

+

Reflect はハンドラーからターゲットへの既定の操作を転送するのに役立ちます。

-

例えば、{{jsxref("Reflect.has()")}} を使えば、in 演算子を関数として使うことができます :

+

例えば、{{jsxref("Reflect.has()")}} を使えば、in 演算子を関数として使うことができます。

-
Reflect.has(Object, 'assign') // true
+
Reflect.has(Object, 'assign') // true
 
-

より優れた apply 関数

+

より優れた apply 関数

-

ES5 では、所定の this 値と配列や配列様のオブジェクトとして提供される arguments を使って関数を呼び出す {{jsxref("Function.prototype.apply()")}} メソッドがよく使われてきました。

+

ES5 では、所定の this 値と配列や配列風オブジェクトとして提供される arguments を使って関数を呼び出す {{jsxref("Function.prototype.apply()")}} メソッドがよく使われてきました。

-
Function.prototype.apply.call(Math.floor, undefined, [1.75])
+
Function.prototype.apply.call(Math.floor, undefined, [1.75])
 
-

{{jsxref("Reflect.apply")}} を使えば、より簡潔で分かりやすいものにできます :

+

{{jsxref("Reflect.apply")}} を使えば、より簡潔で分かりやすいものにできます。

-
Reflect.apply(Math.floor, undefined, [1.75])
+
Reflect.apply(Math.floor, undefined, [1.75])
 // 1
 
 Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111])
@@ -277,14 +298,14 @@ Reflect.apply(''.charAt, 'ponies', [3])
 // "i"
 
-

プロパティ定義の成否チェック

+

プロパティ定義の成否チェック

-

成功した時はオブジェクトを返し、失敗した時は {{jsxref("TypeError")}} を発生させる {{jsxref("Object.defineProperty")}} では、プロパティを定義する際に発生するエラーを捉えるのに {{jsxref("Statements/try...catch","try...catch")}} ブロックを使おうとしていたでしょう。{{jsxref("Reflect.defineProperty")}} では成功したかどうかによって真偽値を返すので、ここでは {{jsxref("Statements/if...else","if...else")}} ブロックを使えます :

+

{{jsxref("Object.defineProperty")}} は成功すればオブジェクトを返し、そうでなければ {{jsxref("TypeError")}} を投げるので、 {{jsxref("Statements/try...catch","try...catch")}} ブロックを使って、プロパティの定義中に発生したエラーを捉えます。 {{jsxref("Reflect.defineProperty")}} は成功のステータスを論理値で返すので、ここでは {{jsxref("Statements/if...else","if...else")}} ブロックを使うだけでよいのです。

-
if (Reflect.defineProperty(target, property, attributes)) {
+
if (Reflect.defineProperty(target, property, attributes)) {
   // 成功した時の処理
 } else {
   // 失敗した時の処理
 }
-

{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}

+

{{PreviousNext("Web/JavaScript/Guide/Iterators_and_Generators", "Web/JavaScript/Guide/Modules")}}

-- cgit v1.2.3-54-g00ecf