1. ホーム
  2. javascript

[解決済み] JavaScriptでReflectオブジェクトは何をするのですか?

2022-11-02 08:27:11

質問

少し前に MDN で空白のスタブを見かけました。 Reflect オブジェクトの空白のスタブを見たのですが、Google でどうしても見つけることができません。今日、私はこれを見つけました http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect-object を見つけたのですが、レルムとローダーの機能を除けば、Proxyオブジェクトに似ているようです。

基本的に、私が見つけたこのページは Reflect の実装方法を説明しているだけなのか、それとも私がその文言を理解できないだけなのかわかりません。どなたか、一般的に Reflect のメソッドが何をするものなのか、どなたか説明していただけないでしょうか。

例えば、私が見つけたページでは、次のように呼び出しています。 Reflect.apply ( target, thisArgument, argumentsList ) を呼び出すと "引数 thisArgument と args でターゲットの [[Call]] 内部メソッドを呼び出した結果を返す." と書かれていますが、これは単に target.apply(thisArgument, argumentsList) ?

更新しました。

Blue さんのおかげで、wiki にこんなページがありました。 http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api&s=reflect 私の知る限りでは、reflect オブジェクトは転送を容易にするためにプロキシでトラップできるすべてのアクションのメソッドバージョンを提供すると書いてある。しかし、それが完全に必要であるとは思えないので、私には少し奇妙に思えます。しかし、それはそれよりももう少し多くのことをするようです。 double-lifting と言っていますが、これは古いプロキシ仕様を指しています。

どのように解決するのですか?

UPDATE 2015です。 で指摘されているように 7日 's 答え , ES6 (ECMAScript 2015)が確定した今、より適切なドキュメントが利用できるようになったのです。


オリジナルの回答((歴史的な)理解と余分な例のために) :

Reflection proposal に進行しているようです。 ECMAScript 6 仕様書草案 . この文書では、現在 Reflect -オブジェクトのメソッドの概要を説明し、以下の点についてのみ記述しています。 Reflect -オブジェクト自身について以下のように記述しています。

Reflectオブジェクトは1つの普通のオブジェクトです。



Reflectオブジェクトの内部スロット[[Prototype]]の値は、標準的な組み込みObject prototypeオブジェクト(19.1.3)です。



Reflectオブジェクトは関数オブジェクトではありません。内部メソッドである [[Construct]] を持ちません。 新しい 演算子でコンストラクタとして使用することはできません。また、Reflect オブジェクトは [[Call]] 内部メソッドを持ちませんので、 Reflect オブジェクトを関数として呼び出すことはできません。

しかし、その目的についての短い説明が ES ハーモニー :

reflect "モジュールは複数の役割を担っています。
  • 今、私たちはモジュールを持っているので、 "@reflect "モジュールは、以前Object上で定義された多くの反射メソッドのための、 より自然な場所です。 後方互換性の目的のために、Object上の静的メソッドが消えることはないでしょう。しかしながら、新しいメソッドは Object コンストラクタよりもむしろ "@reflect" モジュールに追加されるべきでしょう。
  • プロキシのための自然なホームで、グローバルな Proxy バインディングの必要性を回避します。
  • このモジュールのほとんどのメソッドは、Proxy トラップに一対一で対応します。プロキシハンドラは、以下に示すように、便利に操作を進めるためにこれらのメソッドを必要とします。





で、その Reflect オブジェクトは多くのユーティリティ関数を提供しますが、その多くはグローバルなオブジェクトで定義された ES5 メソッドと重複しているように見えます。

しかし、それは、これが解決しようとする既存の問題、またはどのような機能が追加されるかを本当に説明していません。私はこれがシム化されるのではないかと疑い、実際、上記の調和仕様へのリンクは これらのメソッドの非標準的な、近似的な実装' .

このコードを調べると、その使用方法について(さらに)アイデアが得られますが、ありがたいことに、このコードの概要を説明した wiki もあります。 Reflect オブジェクトが有用である多くの理由 :

(であるため、そのソースから今後の参考のために以下のテキストをコピー(およびフォーマット)しました)。 だけ の例です。その上、それらは意味を成し、すでに良い説明を持っていて、質問の apply の例に触れています)。



より便利な戻り値

の多くの操作は Reflect で定義された ES5 の操作に似ています。 Object のような Reflect.getOwnPropertyDescriptorReflect.defineProperty . しかし Object.defineProperty(obj, name, desc)obj を返すか、プロパティが正常に定義された場合は TypeError を投げる。 Reflect.defineProperty(obj, name, desc) は、プロパティが正常に定義されたかどうかを示すブーリアンを単に返すように指定されています。これによって、このコードをリファクタリングすることができます。

try {
  Object.defineProperty(obj, name, desc);
  // property defined successfully
} catch (e) {
  // possible failure (and might accidentally catch the wrong exception)
}

これに

if (Reflect.defineProperty(obj, name, desc)) {
  // success
} else {
  // failure
}

このようなブール値の成功ステータスを返す他のメソッドは Reflect.set (プロパティを更新する) です。 Reflect.deleteProperty (プロパティを削除する)。 Reflect.preventExtensions (オブジェクトを拡張不可にする)、そして Reflect.setPrototypeOf (オブジェクトのプロトタイプリンクを更新する)。



ファーストクラスの操作

ES5 では、オブジェクトが obj が特定のプロパティ名を定義しているか継承しているかを検出する方法は、次のように記述します。 (name in obj) . 同様に、あるプロパティを削除するには delete obj[name] . 専用の構文は短くて良いのですが、操作をファーストクラスの値として渡したい場合は、これらの操作を明示的に関数でラップしなければならないことも意味します。

とは Reflect を使えば、これらの操作は容易にファーストクラス関数として定義できます。

Reflect.has(obj, name) は関数と等価で (name in obj)Reflect.deleteProperty(obj, name) と同じことをする関数です。 delete obj[name].



より信頼性の高い機能アプリケーション

ES5 では、関数を呼び出したいとき f を、配列としてパックされた可変数の引数で呼び出したいとします。 args を結合し this の値を obj と書くことができる。

f.apply(obj, args)

しかし f は、意図的であろうがなかろうが、自分自身を定義するオブジェクトである可能性があります。 apply メソッドを定義しています。本当に組み込みの apply 関数が呼ばれることを確認したい場合、典型的には次のように書きます。

Function.prototype.apply.call(f, obj, args)

これは冗長なだけでなく、すぐに理解しづらくなってしまいます。というのも Reflect を使えば、信頼できる関数呼び出しを、より短く、より理解しやすい方法で行うことができます。

Reflect.apply(f, obj, args)



可変引数型コンストラクタ

可変数の引数を持つコンストラクタ関数を呼び出したいとします。ES6では、新しい拡散構文のおかげで、次のようなコードを書くことができるようになります。

var obj = new F(...args)

ES5では、これは書きにくいです。 F.apply または F.call を使えば、引数の数が可変の関数を呼び出すことができますが、引数の数が可変の関数には F.construct への関数はありません。 new に変更すると、引数の数が可変の関数になります。と共に Reflect で、ES5で、書けるようになりました。

var obj = Reflect.construct(F, args)



Proxy トラップに対するデフォルトの転送動作

を使用する場合 Proxy オブジェクトを使って既存のオブジェクトをラップする場合、操作をインターセプトして何かを行い、その後で "デフォルトの操作を行うことが非常に一般的です。例えば、あるオブジェクトへの全てのプロパティアクセスを単純に記録したいとします。 obj :

var loggedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log("get", target, name);
    // now do the default thing
  }
});

ReflectProxy API は連動して設計されました。 であり、各 Proxy のトラップに対して、対応するメソッドが存在します。 Reflect に対応するメソッドが存在し、それは "does the default thing" です。したがって、Proxy ハンドラの内部でデフォルトの処理を行いたい場合は、常に にある対応するメソッドを呼び出すのが正しい処理です。 Reflect オブジェクトを作成します。

var loggedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log("get", target, name);
    return Reflect.get(target, name);
  }
});

の戻り値の型は Reflect メソッドの戻り値の型と互換性があることが保証されています。 Proxy トラップとの互換性が保証されます。



アクセッサのthis-bindingを制御する

ES5では、一般的なプロパティアクセスやプロパティ更新を行うのはかなり簡単です。例えば

var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update

Reflect.getReflect.set メソッドでも同じことができますが、さらに最後のオプション引数として receiver を明示的に設定することができます。 this -バインディングを明示的に設定することができます。

var name = ... // get property name as a string
Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper`
Reflect.set(obj, name, value, wrapper)

をラップしているとき、これは時々役に立ちます。 obj をラップしていて、アクセッサ内の自己送信をラッパーにルーティングさせたい場合。 obj が次のように定義されている場合です。

var obj = {
  get foo() { return this.bar(); },
  bar: function() { ... }
}

呼び出し Reflect.get(obj, "foo", wrapper) を呼び出すと this.bar() にリルートされます。 wrapper .



レガシーを避ける __proto__

一部のブラウザで __proto__ は、オブジェクトのプロトタイプにアクセスするための特別なプロパティとして定義されています。ES5 では、新しいメソッド Object.getPrototypeOf(obj) が標準化され、プロトタイプを問い合わせることができるようになりました。 Reflect.getPrototypeOf(obj) は全く同じことをしますが、ただし Reflect は、対応する Reflect.setPrototypeOf(obj, newProto) を定義し、オブジェクトのプロトタイプを設定します。これは、オブジェクトのプロトタイプを更新する新しい ES6 準拠の方法です。

ということに注意してください。 setPrototypeOf また に存在する Object (正しく指摘されているように クヌ 's コメント )!


EDITです。

余談(Qへのコメント宛)です。短くて簡単な Q: ES6 モジュール vs. HTML インポート」についての簡単な回答があります。 で説明されています。 RealmsLoader オブジェクトを作成します。

別の説明として このリンク :

<ブロッククオート

realm オブジェクトは、個別のグローバル環境という概念を抽象化したものです。 独自のグローバルオブジェクト、標準ライブラリのコピー、そして グローバル変数に束縛されない標準的なオブジェクト。 Object.prototype の初期値のような、グローバル変数に束縛されない標準的なオブジェクト) があります。

拡張可能な Web : これは動的な同一生成元である <iframe> をDOM無しで表示します.

言及する価値のあるものですが これはまだ草案であり、石に刻まれた仕様ではありません! ES6なので、ブラウザの互換性には注意してください。

これが役に立つといいのですが!