Proxy ãªãã¸ã§ã¯ãã¯å¥ã®ãªãã¸ã§ã¯ããã©ããããããããã£ããã®ä»ã®èªã¿åã/æ¸ãè¾¼ã¿ãªã©ã®æä½ãã¤ã³ã¿ã¼ã»ãããã¾ããå¿
è¦ã«å¿ãã¦ããããç¬èªã«å¦çãããããªãã¸ã§ã¯ããééçã«ããããå¦çã§ããããã«ãã¾ãã
Proxy ã¯å¤ãã®ã©ã¤ãã©ãªãä¸é¨ã®ãã©ã¦ã¶ãã¬ã¼ã ã¯ã¼ã¯ã§ä½¿ããã¦ãã¾ãããã®ç« ã§ã¯ãå¤ãã®å®è·µçãªã¢ããªã±ã¼ã·ã§ã³ãç´¹ä»ãã¾ãã
Proxy
æ§æ:
let proxy = new Proxy(target, handler)
targetâ ã©ãããããªãã¸ã§ã¯ãã§ãã颿°å«ãä½ã§ãOKã§ããhandlerâ ãããã·è¨å®: æä½ãã¤ã³ã¿ã¼ã»ããããã¡ã½ããã§ãã âãã©ããâ ããã¤ãªãã¸ã§ã¯ãã§ããä¾:getãã©ããã¯targetã®ããããã£ã®èªã¿åãç¨ãsetãã©ããã¯ãtargetã¸ã®ããããã£æ¸ãè¾¼ã¿ç¨ããªã©ã
proxy ã®æä½ã§ã¯ãhandler ã«å¯¾å¿ãããã©ãããããå ´åã¯ãããå®è¡ããã¾ãããã以å¤ã®å ´åã¯ãæä½ã¯ target ã§å®è¡ããã¾ãã
æåã®ä¾ã¨ãã¦ããã©ãããªãã§ãããã·ãä½ã£ã¦ã¿ã¾ãããã:
let target = {};
let proxy = new Proxy(target, {}); // 空ã®ãã³ãã©
proxy.test = 5; // ãããã·ã¸ã®æ¸ã込㿠(1)
alert(target.test); // 5, ããããã£ã target ã§ç¾ãã¾ãã!
alert(proxy.test); // 5, proxy ããã®èªã¿åããã¨ãã§ãã¾ã (2)
for(let key in proxy) alert(key); // test, ã¤ãã¬ã¼ã·ã§ã³ãæ©è½ãã¾ã (3)
ãã©ããããªãã®ã§ãproxy ä¸ã®ãã¹ã¦ã®æä½ã¯ target ã«è»¢éããã¾ãã
- æ¸ãè¾¼ã¿æä½
proxy.test=ã¯targetã«å¤ãè¨å®ãã¾ãã - èªã¿è¾¼ã¿æä½
proxy.testã¯targetããã®å¤ãè¿ãã¾ãã proxyã®ã¤ãã¬ã¼ãã¯ãtargetããã®å¤ãè¿ãã¾ãã
ã覧ã®éãããã©ããããªãå ´å㯠proxy 㯠target ã«å¯¾ããééçãªã©ããã¼ã§ãã
Proxy ã¯ç¹å¥ãª âã¨ãã¾ããã¯ãªãã¸ã§ã¯ã(exotic object)â ã§ããProxy ã¯ç¬èªã®ããããã£ã¯æã£ã¦ãã¾ããã空㮠handler ã®å ´åã¯ãééçã« target ã¸æä½ã転éãã¾ãã
ããã«æ©è½ãæå¹ã«ããããã«ããã©ããã追å ãã¾ãããã
ããã«ãã£ã¦ãä½ãã¤ã³ã¿ã¼ã»ããã§ããã§ãããï¼
ãªãã¸ã§ã¯ãã«å¯¾ããã»ã¨ãã©ã®æä½ã«å¯¾ãã¦ã¯ãJavaScript ã®ä»æ§ã§ ãããã âå
é¨ã¡ã½ããâ ã¨å¼ã°ãããã®ãããã仿§ã§ã¯ããããã©ã®ããã«åä½ããããæãä½ã¬ãã«ã§èª¬æãã¦ãã¾ããä¾ãã°ã [[Get]] ã¯ãããããã£ãèªã¿åãããã®å
é¨ã¡ã½ããã§ã[[Set]] ã¯ããããã£ãæ¸ãè¾¼ãããã®å
é¨ã¡ã½ããããªã©ã§ãããããã®ã¡ã½ããã¯ä»æ§ã§ã®ã¿ä½¿ç¨ããã¦ãããååã使ã£ã¦ããããç´æ¥ä½¿ç¨ãããã¨ã¯ã§ãã¾ããã
ãããã·ã®ãã©ããã¯ãããã®ã¡ã½ããã®å¼ã³åºããã¤ã³ã¿ã¼ã»ãããã¾ãããããã®ã¡ã½ããã¯Proxy specification åã³ä»¥ä¸ã®è¡¨ã«ãªã¹ãããã¦ãã¾ãã
ãã®ãã¼ãã«ã«ããã¹ã¦ã®å
é¨ã½ããã«å¯¾ãããã©ãããããã¾ã: æä½ãã¤ã³ã¿ã¼ã»ããããããã« new Proxy ã® handler ãã©ã¡ã¼ã¿ã«è¿½å ã§ããã¡ã½ããåã§ã:
| å é¨ã¡ã½ãã | ãã³ãã©ã¡ã½ãã | ãã¤çºçããã |
|---|---|---|
[[Get]] |
get |
ããããã£èªã¿åãæ |
[[Set]] |
set |
ããããã£æ¸ãè¾¼ã¿æ |
[[HasProperty]] |
has |
in æ¼ç®å |
[[Delete]] |
deleteProperty |
delete æ¼ç®å |
[[Call]] |
apply |
颿°å¼ã³åºã |
[[Construct]] |
construct |
new æ¼ç®å |
[[GetPrototypeOf]] |
getPrototypeOf |
Object.getPrototypeOf |
[[SetPrototypeOf]] |
setPrototypeOf |
Object.setPrototypeOf |
[[IsExtensible]] |
isExtensible |
Object.isExtensible |
[[PreventExtensions]] |
preventExtensions |
Object.preventExtensions |
[[DefineOwnProperty]] |
defineProperty |
Object.defineProperty, Object.defineProperties |
[[GetOwnProperty]] |
getOwnPropertyDescriptor |
Object.getOwnPropertyDescriptor, for..in, Object.keys/values/entries |
[[OwnPropertyKeys]] |
ownKeys |
Object.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in, Object.keys/values/entries |
JavaScript ã«ã¯ããã¤ãã®ä¸å¤æ¡ä»¶(å é¨ã¡ã½ãã㨠ãã©ããã«ãã£ã¦æºããããã¹ãæ¡ä»¶)ãããã¾ãã
ãã®ã»ã¨ãã©ã¯æ»ãå¤ã«é¢ãã¦ã§ã:
[[Set]]ã¯å¤ãæ£å¸¸ã«æ¸ãè¾¼ã¾ããå ´åã«ã¯trueããããã§ãªããã°falseãè¿ãå¿ è¦ãããã¾ãã[[Delete]]ã¯å¤ãæ£å¸¸ã«åé¤ãããå ´åã«ã¯trueããããã§ãªããã°falseãè¿ãå¿ è¦ãããã¾ãã- â¦ãªã©ã§ãã以ä¸ã®ä¾ã§è©³ããè¦ã¦ããã¾ãã
ä»ã«ã以ä¸ã®ãããªããã¤ãã®ä¸å¤æ¡ä»¶ãããã¾ã:
- proxy ãªãã¸ã§ã¯ãã«é©ç¨ããã
[[GetPrototypeOf]]㯠proxy ãªãã¸ã§ã¯ãã®ã¿ã¼ã²ãããªãã¸ã§ã¯ãã«é©ç¨ããã[[GetPrototypeOf]]ã¨åãå¤ãè¿ããªããã°ãªãã¾ãããã¤ã¾ããproxy ã®ãããã¿ã¤ããåç §ããã¨ã常ã«ã¿ã¼ã²ãããªãã¸ã§ã¯ãã®ãããã¿ã¤ããè¿å´ãããå¿ è¦ãããã¾ãã
traps ã¯ãããã®æä½ãã¤ã³ã¿ã¼ã»ããã§ãã¾ããããããã®ã«ã¼ã«ã«ã¯å¾ãå¿ è¦ãããã¾ãã
ä¸å¤æ¡ä»¶ã¯ãè¨èªæ©è½ã®æ£ããã¨ä¸è²«ããåä½ãä¿è¨¼ãããã®ã§ããå®å ¨ãªä¸å¤æ¡ä»¶ã®ãªã¹ãã¯ ä»æ§ã«ããã¾ãããå¤ãªãã¨ãããªãéãã¯éåãããã¨ã¯ãªãã§ãããã
å®éã®ä¾ã§ãããã©ã®ããã«åä½ããã®ããè¦ã¦ã¿ã¾ãããã
âgetâ ãã©ããã§ã®ããã©ã«ãå¤
æãä¸è¬çãªãã©ãã(traps)ã¯ããããã£ã®èªã¿æ¸ãã§ãã
èªã¿åããã¤ã³ã¿ã¼ã»ããããã«ã¯ãhandler ã« get(target, property, receiver) ãå¿
è¦ã§ãã
ããã¯ããããã£ãèªã¿åãããã¨ãã以ä¸ã®å¼æ°ã§å®è¡ããã¾ãã:
target:new Proxyã®æåã®å¼æ°ã¨ãã¦æ¸¡ãããã¿ã¼ã²ãããªãã¸ã§ã¯ãã§ããpropertyâ ããããã£å,receiver--ã¿ã¼ã²ããããããã£ã getter ã®å ´åãreceiverã¯ãã®å¼ã³åºãã®ä¸ã§thisã¨ãã¦ä½¿ããããªãã¸ã§ã¯ãã§ããé常ãããã¯proxyãªãã¸ã§ã¯ãèªèº«(ãããã¯ãproxy ããç¶æ¿ãã¦ããå ´åã¯ãç¶æ¿ãããªãã¸ã§ã¯ã)ã§ããç¾æç¹ã§ã¯ãã®å¼æ°ã¯ä¸è¦ã§ãã詳細ã«ã¤ãã¦ã¯å¾ã»ã©èª¬æãã¾ãã
ãªãã¸ã§ã¯ãã®ããã©ã«ãå¤ãå®è£
ããã®ã« get ã使ã£ã¦ã¿ã¾ãããã
åå¨ããªãå¤ã®å ´å 0 ãè¿ãæ°å¤é
åãä½ãã¾ãã
é常ãåå¨ããªãå¤ãåå¾ãããã¨ãã㨠undefined ã«ãªãã¾ãããããã§ã¯é常ã®é
åã«å¯¾ãã¦ãããããã£ãåå¨ããªãå ´åã« 0 ãè¿ããããã·ã§ã©ãããã¾ãã:
let numbers = [0, 1, 2];
numbers = new Proxy(numbers, {
get(target, prop) {
if (prop in target) {
return target[prop];
} else {
return 0; // ããã©ã«ãå¤
}
}
});
alert( numbers[1] ); // 1
alert( numbers[123] ); // 0 (ãã®ãããªé
ç®ã¯ãªã)
ã覧ã®éããget ãã©ããã使ç¨ããã®ã¯é常ã«ç°¡åã§ãã
Proxy ãå©ç¨ããã¨ãä»»æã® âããã©ã«ãå¤â ç¨ã®ãã¸ãã¯ãçµããã¨ãã§ãã¾ãã
æ³åãã¦ãã ããããã¬ã¼ãºã¨ä¸ç·ã«ç¿»è¨³ãæã¤è¾æ¸ãããã¨ãã¾ã:
let dictionary = {
'Hello': 'Hola',
'Bye': 'Adiós'
};
alert( dictionary['Hello'] ); // Hola
alert( dictionary['Welcome'] ); // undefined
ç¾å¨ããã¬ã¼ãºããªãå ´åãdictionary ã®èªã¿åã㯠undefined ãè¿ãã¾ããããããå®éã«ã¯ undefined ãããæªç¿»è¨³ã®ã¾ã¾ã®ãã¬ã¼ãºãæ®ãã»ããããã§ãããªã®ã§ããã®ãããªå ´åã« undefined ã§ã¯ãªããæªç¿»è¨³ã®ãã¬ã¼ãºãè¿ãããã«ãã¾ãããã
ãã®ããã«ã¯ãdirectory ãèªã¿åãæä½ãã¤ã³ã¿ã¼ã»ãããããããã·ã§ã©ãããã¾ãã:
let dictionary = {
'Hello': 'Hola',
'Bye': 'Adiós'
};
dictionary = new Proxy(dictionary, {
get(target, phrase) { // è¾æ¸(dictionary)ããã®ããããã£èªã¿åããã¤ã³ã¿ã¼ã»ãã
if (phrase in target) { // è¾æ¸ã®ä¸ã«ããå ´å
return target[phrase]; // 翻訳ãè¿ãã¾ã
} else {
// ããã§ãªããã°ãã¬ã¼ãºããã®ã¾ã¾è¿ãã¾ã
return phrase;
}
}
});
// è¾æ¸ã§ä»»æã®ãã¬ã¼ãºãæ¤ç´¢ãã¾ã
// è¾æ¸ã«ãªãå ´åã¯ç¿»è¨³ããã¾ãã
alert( dictionary['Hello'] ); // Hola
alert( dictionary['Welcome to Proxy']); // Welcome to Proxy
ãããã·ãã©ã®ããã«å¤æ°ã䏿¸ããããã«æ³¨æãã¦ãã ããã:
dictionary = new Proxy(dictionary, ...);
ãããã·ã¯ã©ãã§ãã¿ã¼ã²ãããªãã¸ã§ã¯ããå®å ¨ã«ç½®ãæããå¿ è¦ãããã¾ãããããã·ãããå¾ã¯ã¿ã¼ã²ãããªãã¸ã§ã¯ããåç §ããªãã§ãã ãããåç §ããã¨ãç°¡åã«å°ç¡ãã«ãªãã¾ãã
âsetâ ãã©ããã§ã®ããªãã¼ã·ã§ã³
æ°å¤å°ç¨ã®é åãã»ããã¨ãã¾ããããå¥ã®åã®å¤ã追å ãããå ´åãã¨ã©ã¼ã«ããå¿ è¦ãããã¾ãã
set ãã©ããã¯ããããã£ãæ¸ãè¾¼ã¾ããã¨ãã«çºçãã¾ãã
set(target, property, value, receiver):
target:new Proxyã®æåã®å¼æ°ã¨ãã¦æ¸¡ãããã¿ã¼ã²ãããªãã¸ã§ã¯ãã§ããproperty: ããããã£åvalue: ããããã£å¤,receiver:getã¨åæ§ã§ãsetter ããããã£ã«é¢ä¿ãã¾ãã
set ãã©ããã¯è¨å®ãæåãã㨠true ãããã以å¤ã®å ´å㯠false (TypeError ãçºç)ãè¿ãå¿
è¦ãããã¾ãã
æ°ããå¤ãæ¤è¨¼ããã®ã«ä½¿ã£ã¦è¦ã¾ããã:
let numbers = [];
numbers = new Proxy(numbers, { // (*)
set(target, prop, val) { // ããããã£ã®æ¸ãè¾¼ã¿ãã¤ã³ã¿ã¼ã»ãã
if (typeof val == 'number') {
target[prop] = val;
return true;
} else {
return false;
}
}
});
numbers.push(1); // è¿½å æå
numbers.push(2); // è¿½å æå
alert("Length is: " + numbers.length); // 2
numbers.push("test"); // TypeError (ãããã·ã® 'set' ã false ãè¿å´)
alert("This line is never reached (error in the line above)");
注ç®ãã¦ãã ãã: é
åã®çµã¿è¾¼ã¿ã®æ©è½ã¯ä¾ç¶ã¨ãã¦åä½ãã¾ã! å¤ã¯ push ã«ãã追å ããã¾ãããlength ããããã£ã¯å¤ã追å ãããã¨ãã«ãªã¼ãã¤ã³ã¯ãªã¡ã³ãããã¾ãããããã·ã¯ä½ãç ´å£ãã¦ãã¾ããã
æã
ã¯ãã§ãã¯å¦çã追å ããã®ã« push ã unshift ã®ãããªãå¤ã追å ããé
åã¡ã½ããã䏿¸ãããå¿
è¦ã¯ããã¾ããããªããªãããããã¯å
é¨çã«ã¯ [[Set]] æä½ã使ç¨ãã¦ããããããã·ã«ããã¤ã³ã¿ã¼ã»ãããããããã§ãã
ãããã£ã¦ãã³ã¼ãã¯ã¯ãªã¼ã³ã§ããç°¡æ½ã§ãã
true ãè¿ãã®ãå¿ããªãã§ãã ããä¸è¨ã®ããã«ãç¶æãã¹ãæ¡ä»¶ãããã¾ãã
set ã®å ´åãæ¸ãè¾¼ã¿ã®æåã«å¯¾ãã¦ã¯ true ãè¿ããªããã°ãªãã¾ããã
ãããå¿ããã false ãè¿ãã¨ãæä½ã¯ TypeError ãããªã¬ã¼ãã¾ãã
âownKeysâ 㨠âgetOwnPropertyDescriptorâ ã«ããã¤ãã¬ã¼ã·ã§ã³
Object.keys, for..in ã«ã¼ãåã³ãªãã¸ã§ã¯ãããããã£ãã¤ãã¬ã¼ãããä»ã®ã»ã¨ãã©ã®ã¡ã½ãã㯠[[OwnPropertyKeys]] å
é¨ã¡ã½ãã(ownKeys ãã©ããã«ããã¤ã³ã¿ã¼ã»ããããã)ã使ç¨ãã¦ããããã£ã®ãªã¹ããåå¾ãã¦ãã¾ãã
ãã®ãããªã¡ã½ããã®è©³ç´°ã¯ç°ãªãã¾ã:
Object.getOwnPropertyNames(obj)㯠âéâ ã·ã³ãã«ãã¼ãè¿ãã¾ããObject.getOwnPropertySymbols(obj)ã¯ã·ã³ãã«ãã¼ãè¿ãã¾ããObject.keys/values()ã¯enumerableãã©ã°(ããããã£ãã©ã°ã«ã¤ãã¦ã¯ããã£ãã¿ã¼ ããããã£ãã©ã°ã¨ãã£ã¹ã¯ãªãã¿ ã«èª¬æãããã¾ã)ãæã¤éã·ã³ãã«ã®ãã¼/ããªã¥ã¼å¤ãè¿ãã¾ããfor..inã¯enumerableãã©ã°ãæã¤éã·ã³ãã«ãã¼ã¨ãããã¿ã¤ããã¼ãã«ã¼ããã¾ãã
â¦ãããããããã¯ãã¹ã¦ãã®å é¨ã¡ã½ããã§å¾ããããªã¹ãããå§ã¾ãã¾ãã
以ä¸ã®ä¾ã§ã¯ãownKeys ãã©ããã使ç¨ã㦠user ã«å¯¾ãã for..in ã«ã¼ããè¡ããã¾ã Object.keys ã Object.values ãè¡ã£ã¦ãã¾ãããããã¯ã¢ã³ãã¼ã¹ã³ã¢ _ ã§å§ã¾ãããããã£ãã¹ããããã¾ãã:
let user = {
name: "John",
age: 30,
_password: "***"
};
user = new Proxy(user, {
ownKeys(target) {
return Object.keys(target).filter(key => !key.startsWith('_'));
}
});
// "ownKeys" 㯠_password ãé¤å¤ãã¾ã
for(let key in user) alert(key); // name, then: age
// ãããã®ã¡ã½ããã¸ãåãå½±é¿ãããã¾ã:
alert( Object.keys(user) ); // name,age
alert( Object.values(user) ); // John,30
ããã¾ã§ã®ã¨ãããæå¾ éãåä½ãã¦ãã¾ãã
ã§ããããããªãã¸ã§ã¯ãã«åå¨ããªããã¼ãè¿ããå ´åãObject.keys ã¯ããããªã¹ããã¾ãã:
let user = { };
user = new Proxy(user, {
ownKeys(target) {
return ['a', 'b', 'c'];
}
});
alert( Object.keys(user) ); // <empty>
ãªãã§ãããï¼çç±ã¯ç°¡åã§ãã: Object.keys 㯠enumerable ãã©ã°ãæã¤ããããã£ã ããè¿ãããã§ããããã確ãããããããã¹ã¦ã®ã¡ã½ããã«å¯¾ãå
é¨ã¡ã½ãã [[GetOwnProperty]] ãå¼ã³åºã,ãã£ã¹ã¯ãªãã¿ ãåå¾ãã¾ããããã¨ãããã§ã¯ããããã£ããªãã®ã§ããã®ãã£ã¹ã¯ãªãã¿ã¯ç©ºã§ãããenumerable ãã©ã°ãããã¾ããããã®ãããã¹ãããããã¾ãã
Object.keys ãããããã£ãè¿ãã«ã¯ãenumerable ä»ãã§ãªãã¸ã§ã¯ãã«åå¨ãããã[[GetOwnProperty]](ãã©ãã㯠getOwnPropertyDescriptor)ã®å¼ã³åºããã¤ã³ã¿ã¼ã»ããããenumerable: true ãæã¤ãã£ã¹ã¯ãªãã¿ãè¿ãã¾ãã
ããã¯ãã®ã³ã¼ãã§ã:
let user = { };
user = new Proxy(user, {
ownKeys(target) { // ããããã£ã®ãªã¹ããåå¾ããããã«ä¸åº¦ã ãå¼ã°ãã¾ã
return ['a', 'b', 'c'];
},
getOwnPropertyDescriptor(target, prop) { // ããããã£æ¯ã«å¼ã°ãã¾ã
return {
enumerable: true,
configurable: true
/* ...other flags, probable "value:..."" */
};
}
});
alert( Object.keys(user) ); // a, b, c
æ¹ãã¦çæãã¦ãã ãã: [[GetOwnProperty]] ãã¤ã³ã¿ã¼ã»ããããå¿
è¦ãããã®ã¯ãããããã£ããªãã¸ã§ã¯ãã«ãªãå ´åã®ã¿ã§ãã
âdeletePropertyâ åã³ä»ã®ãã©ããã§ä¿è·ãããããããã£
ã¢ã³ãã¼ã¹ã³ã¢ _ ã§å§ã¾ãããããã£ãã¡ã½ããã¯å
é¨çãªãã®ã§ããã¨ãããã¨ã¯ãåºãç¥ãããæ
£ç¿ã§ãããããã¯ãªãã¸ã§ã¯ãã®å¤ããã¢ã¯ã»ã¹ãããã¹ãã§ã¯ããã¾ããã
ã§ãããæè¡çã«ã¯å¯è½ã§ã:
let user = {
name: "John",
_password: "secret"
};
alert(user._password); // secret
ãããã·ã使ç¨ãã¦ã_ ã§å§ã¾ãããããã£ã¸ã®ã¢ã¯ã»ã¹ãé²ãã¾ãããã
次ã®ãã©ãããå¿ è¦ã§ã:
get: ãã®ãããªããããã£ã®èªã¿è¾¼ã¿æã«ã¨ã©ã¼ãã¹ãã¼,set: æ¸ãè¾¼ã¿æã«ã¨ã©ã¼ãã¹ãã¼,deleteProperty: å餿ã«ã¨ã©ã¼ãã¹ãã¼,ownKeys:for..inãObject.keysã®ãããªã¡ã½ãããã_ã§å§ã¾ãããããã£ãé¤å¤
ããããã®ã³ã¼ãã§ã:
let user = {
name: "John",
_password: "***"
};
user = new Proxy(user, {
get(target, prop) {
if (prop.startsWith('_')) {
throw new Error("Access denied");
}
let value = target[prop];
return (typeof value === 'function') ? value.bind(target) : value; // (*)
},
set(target, prop, val) { // ããããã£ã®æ¸ãè¾¼ã¿ãã¤ã³ã¿ã¼ã»ãã
if (prop.startsWith('_')) {
throw new Error("Access denied");
} else {
target[prop] = val;
return true;
}
},
deleteProperty(target, prop) { // ããããã£ã®åé¤ãã¤ã³ã¿ã¼ã»ãã
if (prop.startsWith('_')) {
throw new Error("Access denied");
} else {
delete target[prop];
return true;
}
},
ownKeys(target) { // ããããã£ã®ãªã¹ããã¤ã³ã¿ã¼ã»ãã
return Object.keys(target).filter(key => !key.startsWith('_'));
}
});
// "get" 㯠_password ã®èªã¿è¾¼ã¿ã許å¯ãã¾ãã
try {
alert(user._password); // Error: Access denied
} catch(e) { alert(e.message); }
// "set" 㯠_password ã®æ¸ãè¾¼ã¿ã許å¯ãã¾ãã
try {
user._password = "test"; // Error: Access denied
} catch(e) { alert(e.message); }
// "deleteProperty" 㯠_password ã®åé¤ã許å¯ãã¾ãã
try {
delete user._password; // Error: Access denied
} catch(e) { alert(e.message); }
// "ownKeys" 㯠_password ãé¤å¤ãã¾ã
for(let key in user) alert(key); // name
(*) è¡ã® get ãã©ããã®éè¦ãªç¹ã«æ³¨æãã¦ãã ãã:
get(target, prop) {
// ...
let value = target[prop];
return (typeof value === 'function') ? value.bind(target) : value; // (*)
}
ãªã颿°ã®å ´åã« value.bind(target) ãå¼ã³åºãå¿
è¦ãããã®ã§ããããï¼
çç±ã¯ user.checkPassword() ã®ãããªãªãã¸ã§ã¯ãã¡ã½ãã㯠_password ã¸ã¢ã¯ã»ã¹ã§ããå¿
è¦ãããããã§ãã:
user = {
// ...
checkPassword(value) {
// ãªãã¸ã§ã¯ãã¡ã½ãã㯠_password ã¸ã¢ã¯ã»ã¹ã§ããªããã°ããã¾ãã
return value === this._password;
}
}
user.checkPassword() ã®å¼ã³åºãã¯ãããã·ããã user ã this (ãããã®åã®ãªãã¸ã§ã¯ãã this ã«ãªãã¾ã)ã¨ãã¦åå¾ãããããthis._password ã¸ã®ã¢ã¯ã»ã¹ã試ã¿ã㨠get ãã©ãããæ©è½(ããã¯ããããããããã£èªã¿åãã§ããªã¬ã¼ããã¾ã)ããã¨ã©ã¼ãã¹ãã¼ãã¾ãã
ãã®ããã(*) ã®éããªãã¸ã§ã¯ãã¡ã½ããã®ã³ã³ããã¹ããå
ã®ãªãã¸ã§ã¯ãã§ãã target ã§ãã¤ã³ããã¾ãã以éããã®å¼ã³åºãã§ã¯ this ã¨ãã¦ãã©ããã®ãªã target ã使ç¨ãã¾ãã
ãã®è§£æ±ºçã¯ããã¦ãåä½ãã¾ãããã¡ã½ããããããã·ããã¦ããªããªãã¸ã§ã¯ããå¥ã®å ´æã«æ¸¡ãå¯è½æ§ãããããçæ³çã§ã¯ããã¾ãããããã¯æ··ä¹±ã®ãã¨ã«ãªãã¾ã: ã©ãã«ãªãªã¸ãã«ã®ãªãã¸ã§ã¯ãããããã©ãããããã·ããããã®ãªã®ãã
ããã«ããªãã¸ã§ã¯ããä½åº¦ããããã·ãããå¯è½æ§ãããã¾ã(è¤æ°ã®ãããã·ãããããç°ãªã â微調æ´â ããªãã¸ã§ã¯ãã«ããå ´åãããã¾ã)ãã¾ããã¡ã½ããã«ã©ããããã¦ããªããªãã¸ã§ã¯ããæ¸¡ããå ´åãäºæããªãçµæã«ãªãå¯è½æ§ãããã¾ãã
ãããã£ã¦ããã®ãããªãããã·ã¯ä½¿ç¨ããªããã¨ãæ¨å¥¨ãã¾ãã
ã¢ãã³ãª JavaScript ã¨ã³ã¸ã³ã¯ã¯ã©ã¹ã® private ããããã£ããã¤ãã£ãã«ãµãã¼ããã¾ã(# ããå§ã¾ãã¾ã)ãããã«ã¤ãã¦ã¯ãã£ãã¿ã¼ Private / protected ããããã£ã¨ã¡ã½ãã ã§è¨è¼ãã¦ãã¾ãããããã·ã¯å¿
è¦ããã¾ããã
ãã ãããã®ãããªããããã£ã«ãåé¡ã¯ããã¾ããç¹ã«ãããã¯ç¶æ¿ããã¾ããã
âhasâ ãã©ããã使ç¨ãã âç¯å²å â
ä»ã®ä¾ãè¦ã¦ã¿ã¾ãããã
ç¯å²ãæã¤ãªãã¸ã§ã¯ããããã¾ã:
let range = {
start: 1,
end: 10
};
in æ¼ç®åã使ã£ã¦ã æ°å¤ã range ã®ç¯å²å
ã«ãããã確èªãã¾ãã
has ãã©ãã㯠in å¼ã³åºããã¤ã³ã¿ã¼ã»ãããã¾ãã
has(target, property)
targetânew Proxyã¸ã®æåã®å¼æ°ã¨ãã¦æ¸¡ãããã¿ã¼ã²ãããªãã¸ã§ã¯ãpropertyâ ããããã£å
ãã¢ã§ã:
let range = {
start: 1,
end: 10
};
range = new Proxy(range, {
has(target, prop) {
return prop >= target.start && prop <= target.end
}
});
alert(5 in range); // true
alert(50 in range); // false
è¯ãç³è¡£æ§æã§ãããããã«å®è£ ãã¨ã¦ãç°¡åã§ãã
Wrapping functions: âapplyâ
颿°ã®å¨ãã«å¯¾ãã¦ãåæ§ã« proxy ãã©ãããããã¨ãã§ãã¾ãã
apply(target, thisArg, args) ãã©ããã¯ãããã·ã颿°ã¨ãã¦å¼ã³åºãããå¦çããã¾ã:
targetã¯ã¿ã¼ã²ãããªãã¸ã§ã¯ãã§ã(JavaScript ã§ã¯é¢æ°ã¯ãªãã¸ã§ã¯ãã§ã),thisArgã¯thisã®å¤ã§ãargsã¯å¼æ°ã®ãªã¹ãã§ã
ä¾ãã°ããã£ãã¿ã¼ ãã³ã¬ã¼ã¿ã¨è»¢é, call/apply ã§è¡ã£ã delay(f, ms) ãã³ã¬ã¼ã¿ãæãåºãã¦ãã ããã
ãã®ãã£ãã¿ã¼ã§ã¯ãproxy ã使ããã«å®ç¾ãã¾ãããdelay(f, ms) ã®å¼ã³åºãã¯ãms ããªç§å¾ã« f ã®å¼ã³åºããè¡ã颿°ãè¿ãã¾ããã
ããã¯ä»¥åã®é¢æ°ãã¼ã¹ã®å®è£ ã§ã:
function delay(f, ms) {
// ã¿ã¤ã ã¢ã¦ãå¾ã« f ã¸ã®å¼ã³åºããæ¸¡ãã©ããã¼é¢æ°ãè¿ãã¾ã
return function() { // (*)
setTimeout(() => f.apply(this, arguments), ms);
};
}
function sayHi(user) {
alert(`Hello, ${user}!`);
}
// ãã®ã©ãããããã¨ãsahHi å¼ã³åºã㯠3ç§éé
å»¶ãã¾ã
sayHi = delay(sayHi, 3000);
sayHi("John"); // Hello, John! (3ç§å¾)
ãã§ã«ã覧ã«ãªã£ãããã«ãããã¯ã»ã¼ã»ã¼æ©è½ãã¾ããã©ããã¼é¢æ° (*) ã¯ã¿ã¤ã ã¢ã¦ãå¾ã«å¼ã³åºããå®è¡ãã¾ãã
ããããã©ããã¼é¢æ°ã¯ããããã£ã®èªã¿æ¸ãæä½ãªã©ã¯è»¢éãã¾ãããã©ããããå¾ãname ã length ãªã©ã®å
ã®é¢æ°ã®ããããã£ã¸ã®ã¢ã¯ã»ã¹ã¯å¤±ããã¾ãã:
function delay(f, ms) {
return function() {
setTimeout(() => f.apply(this, arguments), ms);
};
}
function sayHi(user) {
alert(`Hello, ${user}!`);
}
alert(sayHi.length); // 1 (function.length ã¯å®£è¨ããã颿°ã®å¼æ°ã®æ°ãè¿ãã¾ã)
sayHi = delay(sayHi, 3000);
alert(sayHi.length); // 0 (ã©ããã¼å¾ã¯å¼æ°ã¯ 0 ã§ã)
Proxy ã¯ãã¹ã¦ãã¿ã¼ã²ãããªãã¸ã§ã¯ãã«è»¢éããã®ã§ãã¯ããã«å¼·åã§ãã
颿°ã©ããã³ã°ã®ä»£ããã« Proxy ã使ã£ã¦è¦ã¾ããã:
function delay(f, ms) {
return new Proxy(f, {
apply(target, thisArg, args) {
setTimeout(() => target.apply(thisArg, args), ms);
}
});
}
function sayHi(user) {
alert(`Hello, ${user}!`);
}
sayHi = delay(sayHi, 3000);
alert(sayHi.length); // 1 (*) ãããã·ã¯ length æä½ãã¿ã¼ã²ããã«è»¢éãã¾ã
sayHi("John"); // Hello, John! (3ç§å¾)
çµæã¯åãã§ãããå¼ã³åºãã ãã§ãªãããããã·ä¸ã®ãã¹ã¦ã®æä½ã¯å
ã®é¢æ°ã«è»¢éããã¾ãããã®ãããè¡ (*) ã§ sayHi.length ã¯ã©ããã³ã°å¾ãæ£ããå¤ãè¿ãã¾ãã
ããã§ âãããªãããªâ ã©ããã¼ãæã«å ¥ãã¾ããã
ä»ã«ããã©ããã¯ããã¾ã: å®å ¨ãªãªã¹ãã¯ãã®ãã£ãã¿ã¼ã®æåã«ã®ãã¦ãã¾ãããããã®ä½¿ç¨ãã¿ã¼ã³ã¯ä¸è¨ã¨åãã§ãã
Reflect
Reflect 㯠Proxy ã®ä½æãç°¡åã«ããçµã¿è¾¼ã¿ã®ãªãã¸ã§ã¯ãã§ãã
以å説æããã¨ããã[[Get]], [[Set]] ããã®ä»ã®å
é¨ã¡ã½ããã¯ä»æ§ä¸ã®ãã®ã§ãããç´æ¥å¼ã³åºããã¨ã¯ã§ãã¾ããã
Reflect ãªãã¸ã§ã¯ãã¯ãããããããå¯è½ã«ãã¾ããããã®ãã¤ã¡ã½ããã¯å
é¨ã¡ã½ããã®æå°éã®ã©ããã¼ã§ãã
ããã§ã¯ãæä½ã¨ãããã¨åããã¨ããã Reflect å¼ã³åºãã®ä¾ã示ãã¾ã:
| æä½ | Reflect å¼ã³åºã |
å é¨ã¡ã½ãã |
|---|---|---|
obj[prop] |
Reflect.get(obj, prop) |
[[Get]] |
obj[prop] = value |
Reflect.set(obj, prop, value) |
[[Set]] |
delete obj[prop] |
Reflect.deleteProperty(obj, prop) |
[[HasProperty]] |
new F(value) |
Reflect.construct(F, value) |
[[Construct]] |
| ⦠| ⦠| ⦠|
ä¾:
let user = {};
Reflect.set(user, 'name', 'John');
alert(user.name); // John
ç¹ã«ãReflect ã§ã¯æ¼ç®å (new, deleteâ¦) ã颿°(Reflect.construct, Reflect.deleteProperty, â¦)ã¨ãã¦å¼ã³åºããã¨ãã§ãã¾ããããã¯è峿·±ãæ©è½ã§ãããããã§ã¯å¥ã«éè¦ãªé¨åãããã¾ãã
Proxy ã§ãã©ããå¯è½ãªãã¹ã¦ã®å
é¨ã¡ã½ããã«å¯¾ããReflect ã«ã¯ Proxy ãã©ããã¨åãååã弿°ãæã¤å¯¾å¿ããã¡ã½ãããããã¾ãã
ãããã£ã¦ãReflect ã使ã£ã¦æä½ãå
ã®ãªãã¸ã§ã¯ãã«è»¢éãããã¨ãã§ãã¾ãã
ãã®ä¾ã§ã¯ãget 㨠set ã®ä¸¡æ¹ã®ãã©ããããèªã¿æ¸ãæä½ããªãã¸ã§ã¯ãã¸ééç(åå¨ããªããã®ããã«)ã«è»¢éããã¡ãã»ã¼ã¸ã表示ãã¾ãã:
let user = {
name: "John",
};
user = new Proxy(user, {
get(target, prop, receiver) {
alert(`GET ${prop}`);
return Reflect.get(target, prop, receiver); // (1)
},
set(target, prop, val, receiver) {
alert(`SET ${prop}=${val}`);
return Reflect.set(target, prop, val, receiver); // (2)
}
});
let name = user.name; // "GET name" ã表示
user.name = "Pete"; // "SET name=Pete" ã表示
Here:
Reflect.getã¯ãªãã¸ã§ã¯ãããããã£ãèªã¿åãã¾ããReflect.setã¯ãªãã¸ã§ã¯ãããããã£ã®æ¸ãè¾¼ã¿ãè¡ããæåããã°trueãè¿ãã¾ãããã以å¤ã®å ´åã¯falseãè¿ãã¾ãã
ã¤ã¾ãããã¹ã¦ã¯åç´ã§ã: ãã©ãããå¼ã³åºãããªãã¸ã§ã¯ãã«è»¢éãããå ´åãåã弿°ã§ Reflect.<method> ãå¼ã¹ã°ããã§ãã
ã»ã¨ãã©ã®å ´åã§ãReflect ã使ããã¨ãªãåããã¨ãã§ãã¾ããä¾ãã°ãããããã£ã®èªã¿åã Reflect.get(target, prop, receiver) 㯠target[prop] ã«ç½®ãæãããã¨ãã§ãã¾ããã§ãããéè¦ãªæå³åããããã¾ãã
ã²ãã¿ã¼(getter)ã®ãããã·
ãªã Reflect.get ãåªãã¦ããçç±ã示ããã¢ãè¦ã¦ã¿ã¾ããããåããã¦ããªã get/set ãï¼çªç®ã®å¼æ° receiver ãæã£ã¦ããã®ã(ããã¯ä»¥åã¯ä½¿ç¨ãã¦ãã¾ããã§ãã)ãè¦ã¦ããã¾ãããã
_name ããããã£ãã㤠user ãªãã¸ã§ã¯ããããããã®ã²ãã¿ã¼ããã¾ã:
ããã¯ãã®ãããã·ã§ã:
let user = {
_name: "Guest",
get name() {
return this._name;
}
};
let userProxy = new Proxy(user, {
get(target, prop, receiver) {
return target[prop];
}
});
alert(userProxy.name); // Guest
ããã§ã¯ãget ãã©ããã¯æç½ã§ããå
ã®ããããã£ãè¿ããä»ã«ã¯ä½ããã¦ãã¾ãããä»åã®ä¾ã§ã¯ããã§ååã§ãã
ä»ã®ã¨ãããã¹ã¦åé¡ããã¾ãããã§ã¯ä¾ãããå°ãè¤éã«ãã¦ã¿ã¾ãããã
user ããå¥ã®ãªãã¸ã§ã¯ã admin ãç¶æ¿ããã¨ãæ£ãããªãæ¯ãèããèµ·ãã¾ã:
let user = {
_name: "Guest",
get name() {
return this._name;
}
};
let userProxy = new Proxy(user, {
get(target, prop, receiver) {
return target[prop]; // (*) target = user
}
});
let admin = {
__proto__: userProxy,
_name: "Admin"
};
// æå¾
å¤: Admin
alert(admin.name); // åºå: Guest (?!?)
admin.name ã®èªã¿åã㯠"Guest" ã§ã¯ãªã "Admin" ãè¿ãã¹ãã§ã!
ä½ãèµ·ããã®ã§ããããï¼ç¶æ¿ã«ãªã«ãåé¡ããã£ãã®ã§ããããï¼
ã§ããããããã·ãåé¤ããã¨ãã¹ã¦æå¾ éãã«åä½ãã¾ãã
åé¡ã¯è¡ (*) ã®ãããã·ã®ä¸ã«ããã¾ãã
-
admin.nameãèªã¿åãã¨ããadminãªãã¸ã§ã¯ãã«ã¯ãã®ãããªããããã£ã¯ãªããããæ¤ç´¢ã¯ãã®ãããã¿ã¤ãã«é²ã¿ã¾ãã -
ãããã¿ã¤ãã¯
userProxyã§ãã -
ãããã·ãã
nameããããã£ãèªã¿åãã¨ãgetãã©ãããçºçããè¡(*)ã§target[prop]ã«ããå ã®ãªãã¸ã§ã¯ãããè¿å´ããã¾ããpropãã²ãã¿ã¼ã§ããå ´åãtarget[prop]ã®å¼ã³åºãã¯ã³ã³ããã¹ãthis=targetã§ã³ã¼ããå®è¡ããã¾ãããã®ãããçµæã¯å ã®ãªãã¸ã§ã¯ãtarget, ã¤ã¾ãuserããã®this._nameã«ãªãã¾ãã
ãããä¿®æ£ããã«ã¯ãget ãã©ããã®3çªç®ã®å¼æ°ã§ãã receiver ãå¿
è¦ã§ããããã«ããã²ãã¿ã¼ã«æ£ãã this ãæ¸¡ããã¨ãã§ãã¾ããä»åã®ã±ã¼ã¹ã ã¨ãadmin ã§ãã
ã©ããã£ã¦ã²ãã¿ã¼ã¸ã³ã³ããã¹ããæ¸¡ãã®ã§ãããï¼é常ã®é¢æ°ã§ã¯ call/apply ã使ãã¾ãããããã¯ã²ãã¿ã¼ãªã®ã§ âå¼ã³åºãããâ ã®ã§ã¯ãªããåãªãã¢ã¯ã»ã¹ã§ãã
Reflect.get ã¯ããããããã¨ãã§ãã¾ããããã使ããã¨ã§ãã¹ã¦ã䏿ãåãã¾ãã
ä¿®æ£ãããããªã¢ã³ãã§ã:
let user = {
_name: "Guest",
get name() {
return this._name;
}
};
let userProxy = new Proxy(user, {
get(target, prop, receiver) { // receiver = admin
return Reflect.get(target, prop, receiver); // (*)
}
});
let admin = {
__proto__: userProxy,
_name: "Admin"
};
alert(admin.name); // Admin
ä¸ã®ã³ã¼ãã§ã¯ãæ£ãã this (ã¤ã¾ã admin) ã¸ã®åç
§ãç¶æãã receiver ã¯ãè¡ (*) ã§ Reflect.get ã使ç¨ããã²ãã¿ã¼ã«æ¸¡ããã¾ãã
ãã©ãããããã«çãæ¸ããã¨ãã§ãã¾ã:
get(target, prop, receiver) {
return Reflect.get(...arguments);
}
Reflect å¼ã³åºãã¯ãã©ããã¨ã¾ã£ããåãååãä»ãããã¦ãããåã弿°ãåãä»ãã¾ããç¹å¥ã«ãã®ããã«è¨è¨ããã¾ããã
ãããã£ã¦ãreturn Reflect... ã¯å®å
¨ãã¤èããã¾ã§ããªãåãããããææ®µã§æä½ã転éãããã¨ãã§ãã¾ãã
ãããã·ã®å¶é
ãããã·ã¯æ¢åã®ãªãã¸ã§ã¯ãã®åä½ãæãä½ãã¬ãã«ã§å¤æ´ããã微調æ´ããç¬èªã®æ¹æ³ãæä¾ãã¾ããããã§ãå®ç§ã§ã¯ããã¾ãããããã¤ãå¶éãããã¾ãã
çµã¿è¾¼ã¿ãªãã¸ã§ã¯ã: å é¨ã¹ããã(Internal slots)
Map, Set, Date, Promise ãªã©ã®å¤ãã®çµã¿è¾¼ã¿ãªãã¸ã§ã¯ãã¯ããããã âå
é¨ã¹ãããâ ã使ç¨ãã¾ãã
ãããã¯ããããã£ã«ä¼¼ã¦ãã¾ãããå
é¨ã§ä»æ§å°ç¨ã®ç®çã§äºç´ããã¦ãã¾ããä¾ãã°ãMap ã¯å
é¨ã¹ããã [[MapData]] ã«ã¢ã¤ãã ãä¿åãã¾ããçµã¿è¾¼ã¿ã®ã¡ã½ããã¯ã[[Get]]/[[Set]] å
é¨ã¡ã½ããçµç±ã§ã¯ãªããç´æ¥ã¢ã¯ã»ã¹ãã¾ãããã®ãããProxy ã¯ã¤ã³ã¿ã¼ã»ãããããã¨ãã§ãã¾ããã
å é¨ã®è©±ãªã®ã«æ°ã«ããå¿ è¦ã¯ããã®ã§ããããï¼
ããã«åé¡ãããã¾ãããã®ãããªçµã¿è¾¼ã¿ã®ãªãã¸ã§ã¯ãããããã·ãããã¨ããããã·ã¯ãããã®å é¨ã¹ããããæããªããããçµã¿è¾¼ã¿ã®ã¡ã½ããã¯å¤±æãã¾ãã
ä¾:
let map = new Map();
let proxy = new Proxy(map, {});
proxy.set('test', 1); // Error
å
é¨çã«ãMap ã¯ãã¹ã¦ã®ãã¼ã¿ã [[MapData]] å
é¨ã¹ãããã«ä¿åãã¾ãããããã·ã¯ãã®ãããªã¹ãããã¯ããã¾ãããçµã¿è¾¼ã¿ã®ã¡ã½ãã Map.prototype.set ã¡ã½ããã¯å
é¨ãããã㣠this.[[MapData]] ã«ã¢ã¯ã»ã¹ãããã¨ãã¾ãããthis=proxy ãªã®ã§ proxy å
ã«ã¯è¦ã¤ãããã¨ãã§ãã失æãã¾ãã
幸ããªãã¨ã«ãä¿®æ£ããæ¹æ³ãããã¾ã:
let map = new Map();
let proxy = new Proxy(map, {
get(target, prop, receiver) {
let value = Reflect.get(...arguments);
return typeof value == 'function' ? value.bind(target) : value;
}
});
proxy.set('test', 1);
alert(proxy.get('test')); // 1 (works!)
ä¸ã®ä¾ã§ã¯ãget ãã©ãã㯠map.set ãªã©ã®é¢æ°ããããã£ãã¿ã¼ã²ãããªãã¸ã§ã¯ã(map)èªèº«ã«ãã¤ã³ãããã®ã§ãåé¡ãªãåä½ãã¾ãã
ããã¾ã§ã®ä¾ã¨ã¯éããproxy.set(...) å
ã§ã® this ã®å¤ã¯ proxy ã§ã¯ãªãå
ã® map ã«ãªãã¾ãããã®ãããset ã®å
é¨å®è£
ã this.[[MapData]] å
é¨ã¹ãããã«ã¢ã¯ã»ã¹ããã®ã¯æåãã¾ãã
Array ã«ã¯å
é¨ã¹ããããããã¾ããæ³¨ç®ãã¹ãä¾å¤ã§ã: çµã¿è¾¼ã¿ã® Array ã¯å
é¨ã¹ãããã使ç¨ãã¦ãã¾ãããArray ã¯ãã£ã¨ä»¥åããåå¨ãã¦ãããã¨ããããæ´å²çãªçç±ã«ãããã®ã§ãã
ãããã£ã¦é åããããã·ããéã«ã¯ãã®ãããªåé¡ã¯èµ·ããã¾ããã
ãã©ã¤ãã¼ããã£ã¼ã«ã
ä¼¼ããããªãã¨ããã©ã¤ãã¼ãã¯ã©ã¹ãã£ã¼ã«ãã§ãèµ·ããã¾ãã
ä¾ãã°ãgetName() ã¡ã½ããã¯ãããã·å¾ã«ãã©ã¤ãã¼ã #name ããããã£ã¸ã¢ã¯ã»ã¹ããã¨å£ãã¾ãã:
class User {
#name = "Guest";
getName() {
return this.#name;
}
}
let user = new User();
user = new Proxy(user, {});
alert(user.getName()); // Error
ããã¯ããã©ã¤ãã¼ããã£ã¼ã«ããå
é¨ã¹ãããã使ç¨ãã¦å®è£
ããã¦ããããã§ããJavaScript ã¯ãããã«ã¢ã¯ã»ã¹ããéã[[Get]]/[[Set]] ã¯ä½¿ç¨ãã¾ããã
getName() ã®å¼ã³åºãã§ã¯ãthis ã®å¤ã¯ãããã·ããã user ã§ããããã©ã¤ãã¼ããã£ã¼ã«ãã®ã¹ããããæã£ã¦ãã¾ããã
ãã®å ´åããã¡ã½ããããã¤ã³ãããæ¹æ³ã§æ©è½ããããã¨ãã§ãã¾ã:
class User {
#name = "Guest";
getName() {
return this.#name;
}
}
let user = new User();
user = new Proxy(user, {
get(target, prop, receiver) {
let value = Reflect.get(...arguments);
return typeof value == 'function' ? value.bind(target) : value;
}
});
alert(user.getName()); // Guest
ãã ãããã®è§£æ±ºçã«ãæ¬ ç¹ãããã¾ãã以å説æããã¨ããããã®æ¹æ³ã¯å ã®ãªãã¸ã§ã¯ããã¡ã½ããã«å ¬éããã®ã§ãã¡ã½ããã®å¦çã«ãã£ã¦ã¯ããã«ãªãã¸ã§ã¯ããæ¸¡ãããå¯è½æ§ããããä»ã®ãããã·ãããæ©è½ãç ´å£ããå¯è½æ§ãããã¾ãã
Proxy != target
Proxy ã¨å ã®ãªãã¸ã§ã¯ãã¯ç°ãªããªãã¸ã§ã¯ãã§ããããã¯å½ç¶ã§ããã
ãªã®ã§ãå ã®ãªãã¸ã§ã¯ãããã¼ã¨ãã¦ä½¿ç¨ãããã®å¾ãããã·ããã¨ããããã·ã¯è¦ã¤ããã¾ããã:
let allUsers = new Set();
class User {
constructor(name) {
this.name = name;
allUsers.add(this);
}
}
let user = new User("John");
alert(allUsers.has(user)); // true
user = new Proxy(user, {});
alert(allUsers.has(user)); // false
ã覧ã®éãããããã·å¾ã¯ã»ãã allUsers ã§ user ãè¦ã¤ãããã¨ãã§ãã¾ããããããã·ã¯ç°ãªããªãã¸ã§ã¯ãã ããã§ãã
=== ãã¤ã³ã¿ã¼ã»ãããããã¨ã¯ã§ãã¾ãããããã·ã¯ new(construct), in(has), delete(deleteProperty)ãªã©ã®å¤ãã®æ¼ç®åãã¤ã³ã¿ã¼ã»ãããããã¨ãã§ãã¾ãã
ãããããªãã¸ã§ã¯ãã¸ã®å³å¯ç価ãã¹ããã¤ã³ã¿ã¼ã»ããããæ¹æ³ã¯ããã¾ããããªãã¸ã§ã¯ãã¯èªèº«ã«ã®ã¿å³å¯ã«çãããä»ã®å¤ã¨ã¯çããããã¾ããã
ãããã£ã¦ããªãã¸ã§ã¯ãã®çä¾¡ãæ¯è¼ãããã¹ã¦ã®æ¼ç®åã¨çµã¿è¾¼ã¿ã®ã¯ã©ã¹ã¯ãªãã¸ã§ã¯ãã¨ãããã·ãåºå¥ãã¾ããããã«ã¯ééçãªæ¿ããã¯ããã¾ããã
åãæ¶ãå¯è½(revocable)ãªãããã·
åãæ¶ãå¯è½(revocable) ãªãããã·ã¯ãç¡å¹ã«ãããã¨ã®ã§ãããããã·ã§ãã
ãªã½ã¼ã¹ã«å¯¾ãã¦ããã¤ã§ãã¢ã¯ã»ã¹ãéããããããã«ãããã¨ãã¾ãããã
ãã®æ¹æ³ã¨ãã¦ã¯ããªã½ã¼ã¹ããã©ãããããªãåãæ¶ãå¯è½ãªãããã·ã§ã©ãããããã¨ã§ãããã®ãããªãããã·ã¯ãªãã¸ã§ã¯ãã¸æä½ã転éãã¤ã¤ããã¤ã§ããããç¡å¹ã«ãããã¨ãã§ãã¾ãã
æ§æã¯æ¬¡ã®éãã§ã:
let {proxy, revoke} = Proxy.revocable(target, handler)
ãã®å¼ã³åºã㯠proxy ã¨ç¡å¹ã«ããããã« revoke 颿°ãæã¤ãªãã¸ã§ã¯ããè¿ãã¾ãã
ä¾:
let object = {
data: "Valuable data"
};
let {proxy, revoke} = Proxy.revocable(object, {});
// ãªãã¸ã§ã¯ãã®ä»£ããã«ãããã·ãã©ããã«æ¸¡ãã¾ã
alert(proxy.data); // Valuable data
// å¾ã§æ¬¡ã®ããã«ãã¾ã
revoke();
// ããã¨ããããã·ã¯æ©è½ããªããªãã¾ã(ç¡å¹åããã¾ãã)
alert(proxy.data); // Error
revoke() å¼ã³åºãã¯ããããã·ããã¿ã¼ã²ãããªãã¸ã§ã¯ãã¸ã®ãã¹ã¦ã®å
é¨åç
§ãåé¤ãã¾ããããã«ããç¹ããããªããªãã¾ãã
åæç¶æ
ã§ãrevoke 㯠proxy ã¨ã¯å¥ãªã®ã§ãç¾å¨ã®ã¹ã³ã¼ãã« revoke ãæ®ããã¾ã¾ãproxy ãæ¸¡ããã¨ãå¯è½ã§ãã
proxy.revoke = revoke ã¨è¨å®ãããã¨ã§ãproxy ã« revoke ã¡ã½ããããã¤ã³ããããã¨ãã§ãã¾ãã
å¥ã®é¸æè¢ã¯ãWeakMap ã使ãããã¼ã¨ã㦠proxy ããå¤ã¨ãã¦å¯¾å¿ãã revoke ããããããã¨ã§ããããã§ãç°¡åã« proxy ã«å¯¾ãã revoke ãè¦ã¤ãããã¨ãã§ãã¾ãã
let revokes = new WeakMap();
let object = {
data: "Valuable data"
};
let {proxy, revoke} = Proxy.revocable(object, {});
revokes.set(proxy, revoke);
// ..later in our code..
revoke = revokes.get(proxy);
revoke();
alert(proxy.data); // Error (revoked)
ããã§ Map ã®ä»£ããã« WeakMap ã使ç¨ãã¦ããã®ã¯ãã¬ãã¼ã¸ã³ã¬ã¯ã·ã§ã³ããããã¯ããªãããã«ããããã§ããproxy ãªãã¸ã§ã¯ãã âå°éä¸å¯è½â ã«ãªã£ã(e.g ãããåç
§ãã夿°ããªããªã£ã)å ´åãWeakMap ãå©ç¨ããã¨ãä¸è¦ã«ãªã£ã revoke ãä¸ç·ã«ã¡ã¢ãªä¸ããåé¤ãããã¨ãã§ãã¾ãã
ãªãã¡ã¬ã³ã¹
ãµããª
Proxy ã¯ãªãã¸ã§ã¯ãã®ã©ããã¼ã§ãããæä½ããªãã¸ã§ã¯ãã¸è»¢éããå¿
è¦ã«å¿ãã¦ãã®ä¸é¨ããã©ãããã¾ãã
ã¯ã©ã¹ã颿°ãå«ãããããã種é¡ã®ãªãã¸ã§ã¯ããã©ãããããã¨ãã§ãã¾ãã
æ§æ:
let proxy = new Proxy(target, {
/* traps */
});
â¦ãã以éã¯ã©ãã§ã target ã®ä»£ããã« proxy ã使ãå¿
è¦ãããã¾ãããããã·ã¯ç¬èªã®ããããã£ãã¡ã½ããã¯æã£ã¦ãã¾ããããã©ãããæå®ããã¦ããã°æä½ããã©ããããããã§ãªããã° target ãªãã¸ã§ã¯ãã«è»¢éãã¾ãã
以ä¸ããã©ãããããã¨ãã§ãã¾ã:
- ããããã£(åå¨ããªããã®ãå«ã)ã®èªã¿åã(
get)ãæ¸ãè¾¼ã¿(set)ãåé¤(deleteProperty) - 颿°å¼ã³åºã(
applyãã©ãã) newæ¼ç®å(constructãã©ãã)- ãã®ä»å¤ãã®ãã©ãã(å®å ¨ãªãªã¹ãã¯ãã®è¨äºã®åé 㨠docsã«ããã¾ãã)
ããã«ãããâä»®æ³ã®â ããããã£ãã¡ã½ããã使ããããããã©ã«ãå¤ããªãã¶ã¼ããã«ãªãã¸ã§ã¯ãã颿°ãã³ã¬ã¼ã¿ãªã©æ§ã ãªãã®ãå®è£ ãããã¨ãã§ãã¾ãã
ã¾ããç°ãªããããã·ã§è¤æ°åãªãã¸ã§ã¯ããã©ããããæ©è½ã®æ§ã ãªå´é¢ã§ãªãã¸ã§ã¯ããã³ã¬ã¼ããããã¨ãå¯è½ã§ãã
Reflect API 㯠Proxy ãè£å®ããããã®ãã®ã¨ãã¦è¨è¨ããã¦ãã¾ãããã¹ã¦ã® Proxy ãã©ããã«å¯¾ãã¦ãåã弿°ãæã¤ Reflect å¼ã³åºããããã¾ãããããã使ç¨ãã¦ã¿ã¼ã²ãããªãã¸ã§ã¯ãã«è»¢éããå¿
è¦ãããã¾ãã
ãããã·ã«ã¯ããã¤ãå¶éãããã¾ã:
- çµã¿è¾¼ã¿ã®ãªãã¸ã§ã¯ãã«ã¯ âå é¨ã¹ãããâ ãããããããã¸ã®ã¢ã¯ã»ã¹ã¯ãããã·ãããã¨ã¯ã§ãã¾ãããä¸è¨ã®åé¿çãåç §ãã¦ãã ããã
- ãã©ã¤ãã¼ãã¯ã©ã¹ãã£ã¼ã«ãã«ãåããã¨ãå½ã¦ã¯ã¾ãã¾ãããããã¯å
é¨çã«ã¯ã¹ãããã使ç¨ãã¦å®è£
ããã¦ããããããããã·ãããã¡ã½ããå¼ã³åºãã¯ããããã«ã¢ã¯ã»ã¹ããããã«
thisã¨ãã¦ã¿ã¼ã²ãããªãã¸ã§ã¯ãããã¤å¿ è¦ãããã¾ãã - ãªãã¸ã§ã¯ãã®ç価è©ä¾¡
===ã¯ã¤ã³ã¿ã¼ã»ããã§ãã¾ããã - ããã©ã¼ãã³ã¹: ãã³ããã¼ã¯ã¯ã¨ã³ã¸ã³ã«ããã¾ãããé常ãæãåç´ãªãããã·ã使ç¨ããããããã£ã¸ã®ã¢ã¯ã»ã¹ããã«ãæ°åæéããããã¾ãããããå®éã«ãããåé¡ã«ãªãã®ã¯ä¸é¨ã® âããã«ããã¯â ãªãã¸ã§ã¯ãã®ã¿ã§ãã
ã³ã¡ã³ã
<code>ã¿ã°ã使ã£ã¦ãã ãããè¤æ°è¡ã®å ´åã¯<pre>ãã10è¡ãè¶ ããå ´åã«ã¯ãµã³ãããã¯ã¹ã使ã£ã¦ãã ãã(plnkr, JSBin, codepenâ¦)ã