blog

今日はReflectについて書いてみよう。

Reflectは、オブジェクトを操作するためにES6が提供する新しいAPIです。 2: いくつかのObjectメソッドの戻り結果をより合理的になるように変更します。 3: すべてのObject操作を関...

Jan 10, 2021 · 4 min. read
シェア

Reflectは、オブジェクトを操作するためのES6が提供する新しいAPIです。 その目的は次のとおりです。 1: 明らかに言語内部のメソッドであるObjectオブジェクトのいくつかのメソッドをReflectに置くこと。

例えば今後の新しいメソッドがReflectに配備されることは注目に値する。

2: いくつかの Object メソッドの返り値を修正して、より合理的にします。

 
 Object.defineProperty(obj,name,val)プロパティが定義できない場合、エラーが報告される。
 Reflect.getPrototypeOfメソッドを使用する。.defineProperty(obj,name,val)はfalseを返す。

3: すべてのオブジェクト操作を関数の動作にします。

例:delete、inなど。
 通常の書き方は、delete objである。[name],'assign' in obj
 Reflect記述: Reflect.has(obj,'assign')

4: ReflectのメソッドはProxyオブジェクトのメソッドに対応しています。

Proxyオブジェクトのメソッドであれば、Reflectオブジェクトの対応するメソッドを見つけることができます。

この利点は

Proxy は、対応する Reflect オブジェクトのメソッドを簡単に呼び出すことができます。Proxy が意図するデフォルトの振る舞いを完成させます。

 
Proxy(target, {
set: function(target, name, value, receiver) {
 var success = Reflect.set(target, name, value, receiver);
if (success) {
 console.log('property ' + name + ' on ' + target + ' set to ' + value);
}
 return success;
}});
 
 プロキシのメタプログラミング・アプローチでは、ターゲット・オブジェクトに設定されているアクセサ・プロパティを変更することで
 es6では、オブジェクトの__proto__プロパティは、Object.getPrototypeOf(obj)メソッドを通してしか読むことができない。.defineProperty()と定義する。
 また、プロキシのセットで定義できるようになったので、セットではReflectの.set対応するProxyに設定されたデフォルトの振る舞いを実現する。

5:リフレクトで操作性が向上

 
//  
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
//  
Reflect.apply(Math.floor, undefined, [1.75]) // 1

現在、Reflectには合計13の静的メソッドがあります。

Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

以下は、一般的なリフレクトの静的メソッドの抜粋です。

1) Reflect.apply

Reflect.applyこのメソッドは.prototype.apply.call(func, thisArg, args) 
与えられた関数を thisオブジェクトにバインドして実行する。
一般的に、関数の thisオブジェクトをバインドしたい場合は
fnを書くことができる。.apply(obj,args) 
しかし、関数が独自のapplyメソッドを定義している場合は
関数.prototype.apply.call(fn,obj,args) 
Reflectオブジェクトを使うと、この操作が簡単になる。
 
 //  
 const youngest = Math.min.apply(Math,[1,2,3,4,5,6])
 //  
 const youngest = Reflect.apply(Math.min,Math,[1,2,3,4,5,6])
ここで:数学オブジェクトは、数学的なタスクを実行するために使用されるシステム組み込みオブジェクトである。

2) Reflect.get(ターゲット,名前,受信者)

Reflect.get メソッドは、ターゲット・オブジェクトの name プロパティを検索して返します。

tips:最初のパラメータとしてオブジェクトを渡さなければ、エラーが発生する。

ターゲット・オブジェクトにゲッターが指定されている場合、レシーバーはゲッター呼び出しの this値となります。

tips:
 1:プロパティにゲッターが指定されていない場合は、第3引数の有無にかかわらず、最初のオブジェクトのプロパティの値が返される。
 2:プロパティがゲッターを指定しているが、第3パラメータを渡していない場合、最初のオブジェクトのプロパティの値が返される。

Proxy.setインターセプトの内部でReflect.setが使用され、Receiverが渡されると、Proxy.definePropertyインターセプトがトリガされます。これは、Proxy.setのreceiverパラメータが常に現在のProxyインスタンスを指すためです。

Reflect.setが渡された時点でレシーバーにプロパティを割り当てるのに対し

4):Reflect.has(obj, name)

Reflect.hasメソッドは、objのname内のin演算子に対応しています。

5):Reflect.deleteProperty(obj,name)

Reflect.deletePropertyメソッドは、オブジェクト名の削除に対応しています。

6):Reflect.construct

Reflect.constructメソッドはnew target()と同等で、newを使わずにコンストラクタを呼び出す方法を提供します。

function Greeting(name){
 this.name= name
}
// new  
const instance = new Greeting("ZhangSan」)
// reflect 
const instance = Reflect.construct(Greeting,[' '])
tips:ここで渡される最初のパラメータは、コンストラクタ

7):Reflect.getPrototypeOf(obj)

Reflect.getPrototypeOf メソッドは、オブジェクトの __proto___ プロパティを読み取るために使用します。

Object.getPrototypeOf(obj) に対応します。

tips 
Reflect.getPrototypeOfおよびObject.getPrototypeOf(obj)に対応する。.getPrototypeOfこのメソッドの違いは
引数がオブジェクトでない場合、Object.getPrototypeOfこの引数をオブジェクトに変換してから
Reflect.getPrototypeOfメソッドを使用する。.getPrototypeOfはエラーを報告する。
tips:
 1:対象オブジェクトのプロトタイプを設定できない場合は、Reflectの.setPrototypeoffalseを返す。
 2第一引数がオブジェクトでない場合は、Object.getPrototypeOf(obj)となる。.setPrototypeOfは最初のパラメータそのものを返す。.setPrototypeOfはエラーを報告する。
 3第一引数が未定義またはNULLの場合、Object.getPrototypeOf(obj)は実行されない。.setPrototypeOfprototypeOfメソッドはObject.getPrototypeOf(obj)に対応する。.setPrototypeOfどちらもエラーを報告する。
Read next