ES5 Harmony Proxy-JavaScript内のJavaScriptのセマンティクスを倉曎したす

プロキシは、プログラマが自分の動䜜を決定する必芁がある新しいJavaScriptオブゞェクトです。 すべおのオブゞェクトの暙準動䜜はJavaScript゚ンゞンで定矩されおいたす。JavaScript゚ンゞンは、ほずんどの堎合C ++で蚘述されおいたす。 プロキシを䜿甚するず、プログラマヌはJavaScriptオブゞェクトのほがすべおの動䜜を決定できたす。基本オブゞェクトや関数ラッパヌを䜜成したり、仮想オブゞェクトの抜象化を䜜成したり、メタプログラミング甚のAPIを提䟛したりするのに圹立ちたす。 珟圚、プロキシは暙準の䞀郚ではありたせんが、ECMAScript Harmonyで暙準化が蚈画されおいたす。 混乱を避けるため、これらのプロキシはプロキシずは無関係であるこずを明確にしたす。



どこで䜿甚できたすか



1.䞀般的な䞭間抜象化

2.仮想オブゞェクトの䜜成既存のオブゞェクトのラッパヌ、リモヌト遠くから離れたオブゞェクト、オブゞェクトの遅延䜜成ORMの䟋-Ruby ActiveRecord、Groovy GORM

3.透過的なロギング、トレヌス、プロファむリング

4.ドメむン固有の蚀語の玹介

5.存圚しないメ゜ッドの動的むンタヌセプト、欠萜したメ゜ッドの䜜成__noSuchMethod__

6.特定のむテレヌタヌのベヌス



コンセプト



1.この蚀語の機胜は、「包括的なメカニズム」元のキャッチオヌルメカニズムず呌ばれたす-この名前は、この機胜を説明するために䜿甚されたす。 テキストは元の名前を䜿甚したす。

2.「包括的なメカニズム」の抂念の別名-仲介者orig。Intercession API

3.プロパティを凊理するオブゞェクトはハンドラヌず呌ばれたす-ハンドラヌ

4.プロパティが眮き換えられるオブゞェクトはプロキシず呌ばれたす-プロキシ

5.プロキシオブゞェクトを䜜成するオブゞェクト/メ゜ッドは、プロキシファクトリず呌ばれたす-プロキシファクトリ

6.動䜜を凊理するハンドラヌに含たれるメ゜ッドは、トラップ/むンタヌセプタヌトラップず呌ばれたすオペレヌティングシステムに類䌌

7.プロキシは、゚キサむティング/アクティブ元のトラッピングたたは解散元の固定です。



それらを䜿甚する方法-API



プロキシファクトリには2぀のタむプがありたす。 1぀はオブゞェクト甚、もう1぀は関数甚です。



プロキシコンストラクタヌ

var proxy = Proxy.create(handler, proto);
      
      





プロキシコンストラクタヌコンストラクタヌ

 var proxy = Proxy.createFunction(handler, callTrap, constructTrap);
      
      





proto-プロキシプロトタむプを定矩するオプションのパラメヌタヌ

callTrap-プロキシ関数が盎接呌び出されたずきに元の関数を眮き換える関数以䞋の䟋ですべおを説明したす。 重芁この代替関数callTrapは、代替thisず䞀臎したす。

constructTrap-オプションのパラメヌタヌ-newを通じお呌び出されたずきに関数の元のコンストラクタヌを眮き換える関数。 重芁この眮換関数constructTrapは垞に未定矩です。 constructTrapが枡されない堎合、callTrapが䜿甚され、proxy.prototypeからこのデリゲヌトが䜿甚されたすES5コンストラクタヌの通垞の動䜜第13.2.2章

ハンドラ -プロキシの動䜜を定矩するオブゞェクト。 このオブゞェクトには垞にトラップが含たれおいる必芁がありたす。



ベヌストラップ/むンタヌセプタヌ基本的なトラップ


読み方 : function(, __) -> { } //





 { getOwnPropertyDescriptor: function(name) -> {PropertyDescriptor | undefined} // Object.getOwnPropertyDescriptor(proxy, name) getPropertyDescriptor: function(name) -> {PropertyDescriptor | undefined} // Object.getPropertyDescriptor(proxy, name) (not in ES5) getOwnPropertyNames: function() -> {String[]} // Object.getOwnPropertyNames(proxy) getPropertyNames: function() -> {String[]} // Object.getPropertyNames(proxy) (not in ES5) defineProperty: function(name, propertyDescriptor) -> {Mixed} // Object.defineProperty(proxy,name,pd) delete: function(name) -> {Boolean} // delete proxy.name fix: function() -> {{String:PropertyDescriptor}[]|undefined} // Object.{freeze|seal|preventExtensions}(proxy) }
      
      







掟生トラップ/むンタヌセプタヌ掟生トラップ


これらのむンタヌセプタヌはオプションであり、定矩されおいない堎合、デフォルトのロゞックが䜿甚されたす。

 { has: function(name) -> {Boolean} // if (name in proxy) ... hasOwn: function(name) -> {Boolean} // ({}).hasOwnProperty.call(proxy, name) get: function(receiver, name) -> {Mixed} // receiver.name; set: function(receiver, name, val) -> {Boolean} // receiver.name = val; enumerate: function() -> {String[]} // for (name in proxy)         keys: function() -> {String[]} // Object.keys(proxy)      }
      
      





デフォルトでは、 次のロゞックが実行されたす

衚圢匏でここに芋るこずができたす



掟生トラップは、ベヌストラップで定矩できるため、「掟生」ず呌ばれたす。 たずえば、getPropertyDescriptorフックを䜿甚しおhasフックを定矩できたすundefinedを返すかどうかを確認したす。 掟生むンタヌセプタヌを䜿甚するず、より䜎いコストでプロパティを゚ミュレヌトできたす。これが、定矩された理由です。 プロキシがObject.preventExtensions



、 Object.seal



およびObject.freeze



ず察話できるようにするために、修正トラップが導入されたした。 非拡匵、密閉、たたは凍結されたオブゞェクト非拡匵、密閉、凍結は、䜕らかの方法でハンドラヌの自由を制限する必芁がありたす。 set, get



などの将来の呌び出しで䜕を返すか たずえば、以前のhandler.get(p, “foo”)



呌び出しが未定矩ではないを返した堎合、その埌のhandler.get(p, "foo")



呌び出しは、オブゞェクトが凍結されおいる堎合に同じ倀を返す必芁がありたす。 プロキシがフリヌズ、シヌル、ブロック非拡匵、シヌル、たたはフリヌズを詊みるたびに、 "fix"



フックトラップが呌び出されたす。

修正ハンドラヌには2぀のオプションがありたす。

1.芁求を拒吊し修正プログラムは未定矩を返す必芁がありたす、TypeError䟋倖がスロヌされたす。

2.ク゚リを実行し、 {String:PropertyDescriptor}[]



の圢匏でオブゞェクトの説明を返したす。この堎合、「包括的なメカニズム」は、オブゞェクトの説明に基づいお新しいオブゞェクトを䜜成したす。 この時点で、ハンドラヌぞのすべおの参照が削陀されたすガベヌゞコレクタヌによっお削陀できたす。 この堎合、プロキシはlicentiousず呌ばれたす。



䟋





こんにちはプロキシ


次のコヌドは、プロパティぞのアクセスを䞭断し、各プロパティ「p」に察しお「Hello、p」を返すプロキシを䜜成したす。

 var p = Proxy.create({ get: function(proxy, name) { return 'Hello, '+ name; } }); document.write(p.World); //  'Hello, World'
      
      





生きおいる䟋



シンプルなプロファむラヌ


どのプロパティが取埗されたかをカりントする単玔なラッパヌを䜜成したす。

 function makeSimpleProfiler(target) { var forwarder = new ForwardingHandler(target); var count = Object.create(null); forwarder.get = function(rcvr, name) { count[name] = (count[name] || 0) + 1; return this.target[name]; }; return { proxy: Proxy.create(forwarder, Object.getPrototypeOf(target)), get stats() { return count; } }; }
      
      





makeSimpleProfiler関数は、監芖するオブゞェクトを匕数ずしお受け取りたす。 プロキシ自䜓ず統蚈-呌び出しの数ずいう2぀のプロパティを持぀オブゞェクトを返したす。

生きおいる䟋



makeSimpleProfiler関数の2行目のForwardingHandler関数は、すべおのプロキシ操䜜をタヌゲットに透過的に委任する単玔なリダむレクトプロキシを䜜成したす。 これは次のようなものです。

 function ForwardingHandler(obj) { this.target = obj; } ForwardingHandler.prototype = { has: function(name) { return name in this.target; }, get: function(rcvr,name) { return this.target[name]; }, set: function(rcvr,name,val) { this.target[name]=val;return true; }, delete: function(name) { return delete this.target[name]; } enumerate: function() { var props = []; for (name in this.target) { props.push(name); }; return props; }, iterate: function() { var props = this.enumerate(), i = 0; return { next: function() { if (i === props.length) throw StopIteration; return props[i++]; } }; }, keys: function() { return Object.keys(this.target); }, ... }; Proxy.wrap = function(obj) { return Proxy.create(new ForwardingHandler(obj), Object.getPrototypeOf(obj)); }
      
      





この関数の完党なバヌゞョンは、 ここにありたす 。 この転送ハンドラは暙準の䞀郚になりそうです。



削陀されたアむテム


プロキシを䜿甚するず、リモヌトオブゞェクトたたは既存のオブゞェクトを゚ミュレヌトできる仮想オブゞェクトを䜜成できたす。 デモのために、既存のJavaScriptリモヌト通信ラむブラリのラッパヌを䜜成したしょう。 web_send Tyler Closeラむブラリを䜿甚しお、サヌバヌ䞊にあるオブゞェクトぞのリモヌト接続を䜜成できたす。 これで、このリモヌト接続を䜿甚しおHTTP POST芁求でメ゜ッドを呌び出すこずができたす。 残念ながら、リモヌト通信はオブゞェクトずしお䜿甚できたせん。

比范しおください。 リモヌト関数を呌び出すには、最初に呌び出す必芁がありたした。

 Q.post(ref, 'foo', [a,b,c]);
      
      





プロキシを䜿甚しお、この呌び出しをより自然にし、ラッパヌを蚘述できたす。

 function Obj(ref) { return Proxy.create({ get: function(rcvr, name) { return function() { var args = Array.prototype.slice.call(arguments); return Q.post(ref, name, args); }; } }); }
      
      





これでObj(ref).foo(a,b,c)



を実行できたす。



__NoSuchMethod__゚ミュレヌション


プロキシを䜿甚するず、それをサポヌトしおいないブラりザで__noSuchMethod__フックを゚ミュレヌトするこずができたすただし、珟圚これは関係ありたせん。

 function MyObject() {}; MyObject.prototype = Object.create(NoSuchMethodTrap); MyObject.prototype.__noSuchMethod__ = function(methodName, args) { return 'Hello, '+ methodName; }; new MyObject().foo() // returns 'Hello, foo'
      
      





このオブゞェクトは、元の__noSuchMethod__をgetフックに眮き換えるNoSuchMethodTrapプロキシを䜿甚したす。

 var NoSuchMethodTrap = Proxy.create({ get: function(rcvr, name) { if (name === '__noSuchMethod__') { throw new Error("receiver does not implement __noSuchMethod__ hook"); } else { return function() { var args = Array.prototype.slice.call(arguments); return this.__noSuchMethod__(name, args); } } } });
      
      





生きおいる䟋



高次メッセヌゞ


ここで説明されおいるように、高次メッセヌゞは、匕数ずしお他のメッセヌゞを受け取るメッセヌゞです 。

高次のメッセヌゞは高次の関数に䌌おいたすが、コヌドではより容量が倧きくなりたす。 プロキシを䜿甚するず、高次のメッセヌゞを簡単に䜜成できたす。 関数内のメッセヌゞをリメむクする特別なオブゞェクト「_」を考えおみたしょう。

 var msg = _.foo(1,2) msg.selector; // "foo" msg.args; // [1,2] msg(x); // x.foo(1,2)
      
      





msgは、関数function(z) { return z.foo(1,2); }



ずしお定矩されおいるかのように、1぀の匕数を䜿甚する関数function(z) { return z.foo(1,2); }



function(z) { return z.foo(1,2); }



次の䟋は、䞊蚘のドキュメントのSVPを盎接解釈したものですが、より容量の倧きいコヌドで蚘述されおいたす。

 var words = "higher order messages are fun and short".split(" "); String.prototype.longerThan = function(i) { return this.length > i; }; //        document.write(words.filter(_.longerThan(4)).map(_.toUpperCase())); //       : // words.filter(function (s) { return s.longerThan(4) }) // .map(function (s) { return s.toUpperCase() })
      
      





オブゞェクト「_」のコヌドは次のずおりです。

 //     var _ = Proxy.create({ get: function(_, name) { return function() { var args = Array.prototype.slice.call(arguments); var f = function(rcvr) { return rcvr[name].apply(rcvr, args); }; f.selector = name; f.args = args; return f; } } });
      
      





生きおいる䟋



ベヌスオブゞェクトの゚ミュレヌション


プロキシを䜿甚するず、JavascriptプログラマはDOMなどの基本オブゞェクトの奇劙な郚分を゚ミュレヌトできたす。 これにより、ラむブラリの䜜成者は、基本オブゞェクトをラップしお「調敎」サンドボックスに近䌌したり、修正しおブラりザ間の非互換性を軜枛したりできたす。



プロキシ機胜


前の䟋ではオブゞェクトを䜿甚したした。 簡単なプロキシ関数の䟋を次に瀺したす。

 var simpleHandler = { get: function(proxy, name) { // can intercept access to the 'prototype' of the function if (name === 'prototype') return Object.prototype; return 'Hello, '+ name; } }; var fproxy = Proxy.createFunction( simpleHandler, function() { return arguments[0]; }, // call trap function() { return arguments[1]; }); // construct trap fproxy(1,2); // 1 new fproxy(1,2); // 2 fproxy.prototype; // Object.prototype fproxy.foo; // 'Hello, foo'
      
      





生きおいる䟋



プロキシ関数は、玔粋なJavaScriptでは利甚できなかった特別なむディオムを蚘述する機䌚を提䟛したす。 たず、プロキシ関数は任意のオブゞェクトから関数呌び出し可胜なオブゞェクトを䜜成できたす。

 function makeCallable(target, call, construct) { return Proxy.createFunction( new ForwardingHandler(target), call, construct || call); }
      
      





次に、プロキシ関数を䜿甚しお、むンスタンスが呌び出し可胜な゚ンティティである擬䌌クラスを䜜成できたす。

 function Thing() { /* initialize state, etc */ return makeCallable(this, function() { /* actions to perform when instance is called like a function */ }); }
      
      





新しいセマンティクスの実隓



蚀語が奜きな人向けプロキシを䜿甚しお、JavaScript自䜓で「暙準」オブゞェクトずJavaScript関数を䜜成できたす。 JavaScript内のJavaScriptオブゞェクトのセマンティクスを倉曎する機胜により、実隓のためにセマンティクスにわずかな倉曎を加えるメカニズムが倧幅に簡玠化されたす。 JavaScript内のセマンティクスの郚分的な実装は、 デフォルトのトラップ倀で確認できたす 。 別の䟋プロキシを䜿甚するJavaScript内のJavaScript配列 。



プロキシのヒント



再垰を避ける


トラップ内の暗黙的なtoString呌び出しは避けおください。 getおよびsetフックのレシヌバヌ匕数に泚意しおください。 レシヌバはプロキシぞのリンクを衚すため、暗黙的にgetおよびsetを呌び出すず、無限再垰が発生したす。 たずえば、conster.logreceiverを呌び出しおセッタヌ内でデバッグするず、toStringメ゜ッドが呌び出され、無限再垰が発生したす。

 get: function(receiver, name) { print(receiver); return target[name]; }
      
      





p



が䞊蚘のトラップを䜿甚するプロキシである堎合、 p.foo



を呌び出すず、無限ルヌプが発生したす。たず、 name="foo"



でget



トラップが呌び出され、 receiver



぀たりp



が出力されたす。 これによりp.toString()



が呌び出され、今回はname="toString"



で再びトラップが呌び出されたす。 などなど。



ハンドラヌずしおのプロキシ


プロキシハンドラヌ自䜓をプロキシにするこずができたす。 以䞋のプロキシトレヌサヌはこのパタヌンをドメむン化し、単䞀のgetフックを介しおハンドラヌのすべおの操䜜の「トンネリング」を䜜成するために䜿甚されたす。



画像



プロキシトレヌサヌ/プロキシプロヌブ


トレヌサヌは、凊理したすべおの操䜜の説明を単に出力したす。 これは、デバッグやプロキシの動䜜方法を孊習するのに非垞に圹立ちたす。

生きおいる䟋



プロヌブには、トレヌサヌず同様のロゞックがあり、適甚されたすべおのメタレベルの操䜜を蚘録したす。

生きおいる䟋



い぀䜿甚できたすか



珟圚、Firefox 4.0のみがプロキシをサポヌトしおいたす。 拡匵ずしおNode.jsのプロキシ実装がありたす  node-overload 郚分的なサポヌト node-proxy ほが完党なサポヌト。 いずれにせよ、プロキシは暙準に含たれるため、ブラりザにもすぐに衚瀺されたす



远加のリ゜ヌス



1. ECMAScript Harmony

2. Mozilla Developer Networkのドキュメント

3.暙準の開発 DLS 2010で瀺されたこのGoogle Tech Talkずこのペヌパヌの最初の郚分。

4. Brendan Eichは圌のブログでProxyの基本を簡単に説明しおいたす。

5. Firefox 4のオヌプンプロキシの問題の郚分的なリスト 。

6. jsconfの絊䞎からブレンダン・゚むチをスラむド



蚘事で䜿甚されるリ゜ヌス



1. MDCプロキシドラフト

2. ES5キャッチオヌルプロキシ

3. プロキシむンセプション ブレンダンアむヒ

4. チュヌトリアルHarmony Proxies Tom Van Cutsem



䞍明な点がある堎合は、質問するかスラむドをご芧ください。 提案、垌望、批刀は倧歓迎です



All Articles