![](https://habrastorage.org/web/076/423/2f2/0764232f2001455d83c3ac48a68525e8.jpg)
ã¿ãªããããã«ã¡ã¯ïŒ æè¿ãäžéšã®è¥ãããã³ããšã³ãå ¥æè ãã©ã®ããã«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ã¯äžå¯æ¬ ãªéšåãšèããããšãã§ããŸãïŒäžèšã®äŸãããããããã«ïŒã