アクセス可胜な蚀語でAPI proを反映する





みなさんこんにちは 最近、䞀郚の若いフロント゚ンド入札者がどのようにReflectがJavaScriptであるかを他の若いフロント゚ンド入札者に説明しようずしたこずを聞きたした。 その結果、誰かがこれはプロキシず同じこずだず蚀いたした。 状況は私に冗談を思い出させたした



2぀のマむナヌがありたす。

「これに぀いお䜕か理解できたすか」

-さお、説明できたす。

「それは理解できたすが、これに぀いお䜕か理解できたすか」



そのため、JSでReflectを䜿甚するず、誰かにずっお同じ状況が刀明したした。 それは䜕かを蚀っおいるようですが、どのような目的のためにそれは明確ではありたせん。 最埌に、䟋を挙げお簡単な蚀語でもう䞀床説明する䟡倀があるず思いたした。



最初に、プログラミングに反映されるものを定矩したしょう。

Reflection / Reflect APIは、クラス、むンタヌフェヌス、関数、メ゜ッド、およびモゞュヌルをリバヌス゚ンゞニアリングする機胜を提䟛するAPIです。



ここから、このAPIを䜿甚する理由が少し明確になりたす。 Reflection APIはさたざたなプログラミング蚀語に存圚し、時にはPLによっお課される制限を回避するために䜿甚されたす。 たた、さたざたな補助ナヌティリティの開発や、さたざたなパタヌンむンゞェクションなどなどの実装にも䜿甚されたす。



たずえば、Reflection APIはJavaにありたす。 Javaプログラムの実行䞭に、クラス、むンタヌフェヌス、メ゜ッド、フィヌルド、コンストラクタヌ、および泚釈に関する情報を衚瀺するために䜿甚されたす。 たずえば、JavaでReflectionを䜿甚する堎合、OOPパタヌン-Public Morozovを䜿甚できたす。



PHPにはReflection APIもあり、リバヌス゚ンゞニアリングだけでなく、さたざたな自己文曞化システムで䜿甚されるコメントのdocブロックを受信するこずもできたす。



JavaScriptのReflectは、JavaScript操䜜をむンタヌセプトするメ゜ッドを提䟛する組み蟌みオブゞェクトです。 実際、これは名前空間ですMathなど。 Reflectには、Proxyのメ゜ッドずたったく同じように呌び出される䞀連の関数が含たれおいたす。



これらのメ゜ッドの䞀郚は、ObjectたたはFunctionクラスの察応するメ゜ッドず同じです。 JavaScriptは成長し、倧きく耇雑なJPに倉わりたす。 他の蚀語からのさたざたなものが蚀語に入りたす。 珟圚、Reflect APIは他の蚀語ほどには機胜しおいたせん。 ただし、ただ暙準の䞀郚ではないが既に䜿甚されおいる拡匵提案がありたす。 たずえば、リフレクションメタデヌタ。



JSのReflect名前空間は、コヌドのリファクタリングの結果であるず蚀えたす。 すでにReflect APIの機胜を䜿甚したしたが、これらの機胜はすべお基本クラスObjectに埋め蟌たれおいたす。



メタデヌタの反映/メタデヌタの反映



このAPIは、実行時にオブゞェクトに関する情報を取埗するように蚭蚈されおいたす。 これは提案であり、ただ暙準ではありたせん。 珟圚、Polyphilが積極的に䜿甚されおいたす。 珟圚、Angularで積極的に䜿甚されおいたす。 このAPIを䜿甚しお、Injectずデコレヌタヌアノテヌタヌが実装されたす。



実際、Angularのために、TypeScriptは拡匵デコレヌタ構文で拡匵されおいたす。 デコレヌタの興味深い機胜の1぀は、装食されたプロパティたたはパラメヌタのタむプに関する情報を取埗できるこずです。 これが機胜するには、reflect-metadataラむブラリを接続する必芁がありたす。これは、暙準のReflectオブゞェクトを拡匵し、TS構成でemitDecoratorMetadataオプションを有効にしたす。 その埌、少なくずも1぀のデコレヌタを持぀プロパティの堎合、キヌ「designtype」を指定しおReflect.getMetadataを呌び出すこずができたす。



ReflectずProxyの違いは䜕ですか



Reflectは、オブゞェクトを操䜜するための䟿利なメ゜ッドのセットで、その半分はオブゞェクトから既存のものに曞き換えられたす。 これは、Objectが基本クラスであるため、セマンティクスを改善し、順序を埩元するために行われたしたが、同時に、含たれおはならないメ゜ッドが倚数含たれおいたす。 たた、空のプロトタむプを䜿甚しおオブゞェクトを䜜成するず、リフレクションメ゜ッドは衚瀺されなくなりたす以䞋に䟋を瀺しお、これが䜕を意味するかを瀺したす。



プロキシは、アクセスをむンタヌセプトするハンドラヌがむンストヌルされた新しいオブゞェクトを垞に䜜成するクラスです。 オブゞェクトを䜿甚しおアクションをキャッチし、倉曎するこずができたす。 Reflectは、さたざたなロゞックの実装によく䜿甚されたす。 以䞋に䟋を瀺しお、これを明確に芋るこずができたす。



ナヌスケヌス



それでは、Reflect APIの䜿甚方法を芋おみたしょう。 いく぀かの䟋は長い間知られおいたすが、これらの目的のためだけにObjectクラスのメ゜ッドを䜿甚するこずに慣れおいたす。 しかし、論理的には、Reflectパッケヌゞパッケヌゞ-Javaの甚語からそれらを䜿甚する方が正しいでしょう。



自動生成されたオブゞェクトフィヌルド



オブゞェクトにアクセスするず、オブゞェクトのフィヌルドが自動的に䜜成されるオブゞェクトを䜜成できたす。



const emptyObj = () => new Proxy({}, { get: (target, key, receiver) => ( Reflect.has(target, key) || Reflect.set(target, key, emptyObj()), Reflect.get(target, key, receiver) ) } ) ; const path = emptyObj(); path.to.virtual.node.in.empty.object = 123; console.log(path.to.virtual.node.in.empty.object); // 123
      
      





すべおがクヌルですが、そのようなオブゞェクトをJSONでシリアル化できないため、゚ラヌが発生したす。 マゞックシリアル化メ゜ッドを远加する-toJSON



 console.clear(); const emptyObj = () => new Proxy({}, { get: (target, key, receiver) => ( key == 'toJSON' ? () => target : ( Reflect.has(target, key) || Reflect.set(target, key, emptyObj()), Reflect.get(target, key, receiver) ) ) } ) ; const path = emptyObj(); path.to.virtual.node.in.empty.object = 123; console.log(JSON.stringify(path)); // {"to":{"virtual":{"node":{"in":{"empty":{"object":123}}}}}}
      
      





動的コンストラクタヌ呌び出し



私たちが持っおいたす



 var obj = new F(...args)
      
      





しかし、コンストラクタを動的に呌び出しおオブゞェクトを䜜成できるようにしたいず考えおいたす。 これにはReflect.constructがありたす。



 var obj = Reflect.construct(F, args)
      
      





工堎での䜿甚に必芁な堎合がありたすOOP同性愛者は理解したす。 䟋



 // Old method function Greeting(name) { this.name = name } Greeting.prototype.greet = function() { return `Hello ${this.name}` } function greetingFactory(name) { var instance = Object.create(Greeting.prototype); Greeting.call(instance, name); return instance; } var obj = greetingFactory('Tuturu'); obj.greet();
      
      





2017幎にはどのように曞かれおいたすか



 class Greeting { constructor(name) { this.name = name } greet() { return `Hello ${this.name}` } } const greetingFactory = name => Reflect.construct(Greeting, [name]); const obj = greetingFactory('Tuturu'); obj.greet();
      
      





jQueryの動䜜を繰り返す



次の行は、jQueryを2行で䜜成する方法を瀺しおいたす。



 const $ = document.querySelector.bind(document); Element.prototype.on = Element.prototype.addEventListener;
      
      





䟝存関係のない䜕かをすばやく構築する必芁がある堎合に䟿利であり、長いネむティブ構成を曞くのが面倒です。 ただし、この実装にはマむナスがありたす。nullを操䜜するず䟋倖がスロヌされたす。



 console.log( $('some').innerHTML ); error TypeError: Cannot read property 'innerHTML' of null
      
      





ProxyずReflectを䜿甚しお、この䟋を曞き換えるこずができたす。



 const $ = selector => new Proxy( document.querySelector(selector)||Element, { get: (target, key) => Reflect.get(target, key) } ) ;
      
      





ここで、nullプロパティにアクセスしようずするず、未定矩になりたす。



 console.log( $('some').innerHTML ); // undefined
      
      





では、なぜReflectを䜿甚するのですか



Reflect APIぱラヌ凊理に䟿利です。 たずえば、誰もが呜什を知っおいたす

Object.definePropertyobj、名前、desc



倱敗した堎合、䟋倖がスロヌされたす。 ただし、Reflectはすべおに察しお䟋倖をスロヌするわけではありたせんが、ブヌル倀の結果を返すこずができたす。



 try { Object.defineProperty(obj, name, desc); // property defined successfully } catch (e) { // possible failure (and might accidentally catch the wrong exception) } /* --- OR --- */ if (Reflect.defineProperty(obj, name, desc)) { // success } else { // failure }
      
      





これにより、゚ラヌをtry-catchではなく条件で凊理できたす。 ゚ラヌ凊理でReflect APIを䜿甚する䟋



 try { var foo = Object.freeze({bar: 1}); delete foo.bar; } catch (e) {}
      
      





そしお今、あなたはこのように曞くこずができたす



 var foo = Object.freeze({bar: 1}); if (Reflect.deleteProperty(foo, 'bar')) { console.log('ok'); } else { console.log('error'); }
      
      





しかし、Reflectも䟋倖をスロヌする堎合があるず蚀わなければなりたせん。



䞀郚の゚ントリは短くなっおいたす



さらに苊劎せずに



 Function.prototype.apply.call(func, obj, args) /* --- OR --- */ Reflect.apply.call(func, obj, args)
      
      





行動の違い



蚀葉のない䟋



 Object.getPrototypeOf(1); // undefined Reflect.getPrototypeOf(1); // TypeError
      
      





すべおが明らかなようです。 私たちはそれが優れおいるず結論付けたす。 Reflect APIはより論理的です。



空のプロトタむプを持぀オブゞェクトを操䜜する



䞎えられた



 const myObject = Object.create(null); myObject.foo = 123; myObject.hasOwnProperty === undefined; // true //    : Object.prototype.hasOwnProperty.call( myObject, 'foo' ); // true
      
      





ご芧のずおり、hasOwnPropertyなどのリフレクションメ゜ッドはありたせん。 したがっお、基本クラスのプロトタむプを参照する叀い方法を䜿甚するか、Reflect APIを参照したす。



 Reflect.ownKeys(myObject).includes('foo') // true
      
      





結論



Reflect APIはリファクタリングの結果です。 この名前空間には、以前に基本クラスObject、Function ...に接続されおいたリフレクション関数が含たれ、動䜜ず゚ラヌ凊理が倉曎されたした。 将来、この名前空間は他のリフレクティブツヌルで拡匵されたす。 たた、プロキシを䜿甚する堎合、Reflect APIは䞍可欠な郚分ず考えるこずができたす䞊蚘の䟋からわかるように。



All Articles