ä¸ä¸ª Proxy 对象å
è£
å¦ä¸ä¸ªå¯¹è±¡å¹¶æ¦æªè¯¸å¦è¯»å/åå
¥å±æ§åå
¶ä»æä½ï¼å¯ä»¥éæ©èªè¡å¤çå®ä»¬ï¼æè
éæå°å
许该对象å¤çå®ä»¬ã
Proxy 被ç¨äºäºè®¸å¤åºåæäºæµè§å¨æ¡æ¶ã卿¬æä¸ï¼æä»¬å°çå°è®¸å¤å®é åºç¨ã
Proxy
è¯æ³ï¼
let proxy = new Proxy(target, handler)
targetââ æ¯è¦å è£ ç对象ï¼å¯ä»¥æ¯ä»»ä½ä¸è¥¿ï¼å æ¬å½æ°ãhandlerââ 代çé ç½®ï¼å¸¦æâææå¨âï¼âtrapsâï¼å³æ¦æªæä½çæ¹æ³ï¼çå¯¹è±¡ãæ¯å¦getææå¨ç¨äºè¯»åtargetç屿§ï¼setææå¨ç¨äºåå ¥targetç屿§ï¼ççã
对 proxy è¿è¡æä½ï¼å¦æå¨ handler ä¸åå¨ç¸åºçææå¨ï¼åå®å°è¿è¡ï¼å¹¶ä¸ Proxy ææºä¼å¯¹å
¶è¿è¡å¤çï¼å¦åå°ç´æ¥å¯¹ target è¿è¡å¤çã
é¦å ï¼è®©æä»¬å建ä¸ä¸ªæ²¡æä»»ä½ææå¨ç代çï¼Proxyï¼ï¼
let target = {};
let proxy = new Proxy(target, {}); // 空ç handler 对象
proxy.test = 5; // åå
¥ proxy 对象 (1)
alert(target.test); // 5ï¼test 屿§åºç°å¨äº 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 çéæå
è£
å¨ï¼wrapperï¼ã
Proxy æ¯ä¸ç§ç¹æ®çâå¥å¼å¯¹è±¡ï¼exotic objectï¼âã宿²¡æèªå·±ç屿§ã妿 handler 为空ï¼åéæå°å°æä½è½¬åç» targetã
è¦æ¿æ´»æ´å¤åè½ï¼è®©æä»¬æ·»å ææå¨ã
æä»¬å¯ä»¥ç¨å®ä»¬æ¦æªä»ä¹ï¼
对äºå¯¹è±¡ç大夿°æä½ï¼JavaScript è§è䏿ä¸ä¸ªæè°çâå
鍿¹æ³âï¼å®æè¿°äºæåºå±ç工使¹å¼ãä¾å¦ [[Get]]ï¼ç¨äºè¯»å屿§çå
鍿¹æ³ï¼[[Set]]ï¼ç¨äºåå
¥å±æ§çå
鍿¹æ³ï¼ççãè¿äºæ¹æ³ä»
å¨è§èä¸ä½¿ç¨ï¼æä»¬ä¸è½ç´æ¥éè¿æ¹æ³åè°ç¨å®ä»¬ã
Proxy ææå¨ä¼æ¦æªè¿äºæ¹æ³çè°ç¨ãå®ä»¬å¨ proxy è§è åä¸è¡¨ä¸è¢«ååºã
å¯¹äºæ¯ä¸ªå
鍿¹æ³ï¼æ¤è¡¨ä¸é½æä¸ä¸ªææå¨ï¼å¯ç¨äºæ·»å å° new Proxy ç handler åæ°ä¸ä»¥æ¦æªæä½çæ¹æ³åç§°ï¼
| å 鍿¹æ³ | 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]]ï¼å¿ é¡»è¿åä¸åºç¨äºè¢«ä»£ç对象ç[[GetPrototypeOf]]ç¸åçå¼ãæ¢å¥è¯è¯´ï¼è¯»å代ç对象çååå¿ é¡»å§ç»è¿å被代ç对象çååã
ææå¨å¯ä»¥æ¦æªè¿äºæä½ï¼ä½æ¯å¿ é¡»éµå¾ªä¸é¢è¿äºè§åã
ä¸åéç¡®ä¿è¯è¨åè½çæ£ç¡®åä¸è´çè¡ä¸ºã宿´çä¸åéåè¡¨å¨ è§è ä¸ãå¦æä½ ä¸å奿ªçäºæ ï¼ä½ å¯è½å°±ä¸ä¼è¿åå®ä»¬ã
让æä»¬æ¥ççå®ä»¬æ¯å¦ä½å¨å®é 示ä¾ä¸å·¥ä½çã
带æ âgetâ ææå¨çé»è®¤å¼
æå¸¸è§çææå¨æ¯ç¨äºè¯»å/åå ¥ç屿§ã
è¦æ¦æªè¯»åæä½ï¼handler åºè¯¥æ get(target, property, receiver) æ¹æ³ã
读å屿§æ¶è§¦åè¯¥æ¹æ³ï¼åæ°å¦ä¸ï¼
targetââ æ¯ç®æ 对象ï¼è¯¥å¯¹è±¡è¢«ä½ä¸ºç¬¬ä¸ä¸ªåæ°ä¼ éç»new Proxyï¼propertyââ ç®æ 屿§åï¼receiverââ å¦æç®æ 屿§æ¯ä¸ä¸ª getter 访é®å¨å±æ§ï¼åreceiverå°±æ¯æ¬æ¬¡è¯»å屿§æå¨çthis对象ãé常ï¼è¿å°±æ¯proxy对象æ¬èº«ï¼æè ï¼å¦ææä»¬ä» proxy ç»§æ¿ï¼åæ¯ä»è¯¥ proxy ç»§æ¿ç对象ï¼ãç°å¨æä»¬ä¸éè¦æ¤åæ°ï¼å æ¤ç¨åæä»¬å°å¯¹å ¶è¿è¡è¯¦ç»ä»ç»ã
让æä»¬ç¨ get æ¥å®ç°ä¸ä¸ªå¯¹è±¡çé»è®¤å¼ã
æä»¬å°å建ä¸ä¸ªå¯¹ä¸åå¨çæ°ç»é¡¹è¿å 0 çæ°ç»ã
é常ï¼å½äººä»¬å°è¯è·åä¸åå¨çæ°ç»é¡¹æ¶ï¼ä»ä»¬ä¼å¾å° undefinedï¼ä½æ¯æä»¬å¨è¿å°å¸¸è§æ°ç»å
è£
å°ä»£çï¼proxyï¼ä¸ï¼ä»¥æè·è¯»åæä½ï¼å¹¶å¨æ²¡æè¦è¯»åç屿§çæ¶è¿å 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ã
为æ¤ï¼æä»¬å°æ dictionary å
è£
è¿ä¸ä¸ªæ¦æªè¯»åæä½ç代çï¼
let dictionary = {
'Hello': 'Hola',
'Bye': 'Adiós'
};
dictionary = new Proxy(dictionary, {
get(target, phrase) { // æ¦æªè¯»å屿§æä½
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 访é®å¨å±æ§ç¸å ³ã
妿åå
¥æä½ï¼settingï¼æåï¼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ï¼proxy ç 'set' è¿å falseï¼
alert("This line is never reached (error in the line above)");
请注æï¼æ°ç»çå
å»ºæ¹æ³ä¾ç¶ææï¼å¼è¢«ä½¿ç¨ push æ¹æ³æ·»å å°æ°ç»ãå½å¼è¢«æ·»å å°æ°ç»åï¼æ°ç»ç length 屿§ä¼èªå¨å¢å ãæä»¬ç代ç对象 proxy ä¸ä¼ç ´åä»»ä½ä¸è¥¿ã
æä»¬ä¸å¿
éåè¯¸å¦ push å unshift çæ·»å å
ç´ çæ°ç»æ¹æ³ï¼å°±å¯ä»¥å¨å
¶ä¸æ·»å æ£æ¥ï¼å 为å¨å
é¨å®ä»¬ä½¿ç¨ä»£çææ¦æªç [[Set]] æä½ã
å æ¤ï¼ä»£ç ç®æ´æäºã
trueå¦ä¸æè¿°ï¼è¦ä¿æä¸åéã
å¯¹äº set æä½ï¼å®å¿
须卿ååå
¥æ¶è¿å trueã
妿æä»¬å¿è®°è¿æ ·åï¼æè¿åä»»ä½åï¼falsyï¼å¼ï¼å该æä½å°è§¦å TypeErrorã
ä½¿ç¨ âownKeysâ å âgetOwnPropertyDescriptorâ è¿è¡è¿ä»£
Object.keysï¼for..in 循ç¯å大夿°å
¶ä»éåå¯¹è±¡å±æ§çæ¹æ³é½ä½¿ç¨å
鍿¹æ³ [[OwnPropertyKeys]]ï¼ç± ownKeys ææå¨æ¦æª) æ¥è·å屿§å表ã
è¿äºæ¹æ³å¨ç»è䏿æä¸åï¼
Object.getOwnPropertyNames(obj)è¿åé symbol é®ãObject.getOwnPropertySymbols(obj)è¿å symbol é®ãObject.keys/values()è¿å带æenumerableæ å¿çé symbol é®/å¼ï¼å±æ§æ å¿å¨ 屿§æ å¿å屿§æè¿°ç¬¦ ä¸ç« æè¯¦ç»è®²è§£)ãfor..in循ç¯é忿另æenumerableæ å¿çé symbol é®ï¼ä»¥ååå对象çé®ã
â¦â¦ä½æ¯ææè¿äºé½ä»è¯¥å表å¼å§ã
å¨ä¸é¢è¿ä¸ªç¤ºä¾ä¸ï¼æä»¬ä½¿ç¨ ownKeys ææå¨æ¦æª for..in 对 user çéåï¼å¹¶ä½¿ç¨ 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ï¼ç¶åæ¯ 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]] æ¥è·å å®çæè¿°ç¬¦ï¼descriptorï¼ãå¨è¿éï¼ç±äºæ²¡æå±æ§ï¼å
¶æè¿°ç¬¦ä¸ºç©ºï¼æ²¡æ 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
/* ...å
¶ä»æ å¿ï¼å¯è½æ¯ "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ãç¶åï¼å®ä»¬å°æ¥çè°ç¨å°ä½¿ç¨ target ä½ä¸º thisï¼ä¸ä¼è§¦å任使æå¨ã
è¯¥è§£å³æ¹æ¡é常å¯è¡ï¼ä½å¹¶ä¸çæ³ï¼å 为ä¸ä¸ªæ¹æ³å¯è½ä¼å°æªè¢«ä»£ççå¯¹è±¡ä¼ éå°å ¶ä»å°æ¹ï¼ç¶åæä»¬å°±ä¼é·å ¥å°å¢ï¼åå§å¯¹è±¡å¨åªéï¼è¢«ä»£çç对象å¨åªéï¼
æ¤å¤ï¼ä¸ä¸ªå¯¹è±¡å¯è½ä¼è¢«ä»£ç夿¬¡ï¼å¤ä¸ªä»£çå¯è½ä¼å¯¹è¯¥å¯¹è±¡æ·»å ä¸åçâè°æ´âï¼ï¼å¹¶ä¸å¦ææä»¬å°æªå è£ çå¯¹è±¡ä¼ éç»æ¹æ³ï¼åå¯è½ä¼äº§çææ³ä¸å°çåæã
å æ¤ï¼å¨ä»»ä½å°æ¹é½ä¸åºä½¿ç¨è¿ç§ä»£çã
ç°ä»£ JavaScript 弿åçæ¯æ class ä¸çç§æå±æ§ï¼è¿äºç§æå±æ§ä»¥ # 为åç¼ãå®ä»¬å¨ ç§æçååä¿æ¤ç屿§åæ¹æ³ ä¸ç« ä¸æè¯¦ç»æè¿°ãæ é代çï¼proxyï¼ã
使¯ï¼æ¤ç±»å±æ§æå ¶èªèº«çé®é¢ãç¹å«æ¯ï¼å®ä»¬æ¯ä¸å¯ç»§æ¿çã
带æ âhasâ ææå¨ç âin rangeâ
让æä»¬æ¥çæ´å¤ç¤ºä¾ã
æä»¬æä¸ä¸ª range 对象ï¼
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
æ¼äº®çè¯æ³ç³ï¼ä¸æ¯åï¼èä¸å®ç°èµ·æ¥é常ç®åã
å è£ å½æ°ï¼"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) {
// è¿åä¸ä¸ªå
è£
å¨ï¼wrapperï¼ï¼è¯¥å
è£
å¨å°å¨æ¶é´å°äºçæ¶åå°è°ç¨è½¬åç»å½æ° f
return function() { // (*)
setTimeout(() => f.apply(this, arguments), ms);
};
}
function sayHi(user) {
alert(`Hello, ${user}!`);
}
// å¨è¿è¡è¿ä¸ªå
è£
åï¼sayHi 彿°ä¼è¢«å»¶è¿ 3 ç§å被è°ç¨
sayHi = delay(sayHi, 3000);
sayHi("John"); // Hello, John! (after 3 seconds)
æ£å¦æä»¬æçå°ç飿 ·ï¼å¤§å¤æ°æ
åµä¸å®é½æ¯å¯è¡çãå
è£
彿° (*) å¨å°è¾¾å»¶è¿çæ¶é´ååæ§è¡è°ç¨ã
使¯å
è£
彿°ä¸ä¼è½¬å屿§è¯»å/åå
¥æä½æè
ä»»ä½å
¶ä»æä½ãè¿è¡å
è£
åï¼å°±å¤±å»äºå¯¹åå§å½æ°å±æ§ç访é®ï¼ä¾å¦ nameï¼length åå
¶ä»å±æ§ï¼
function delay(f, ms) {
return function() {
setTimeout(() => f.apply(this, arguments), ms);
};
}
function sayHi(user) {
alert(`Hello, ${user}!`);
}
alert(sayHi.length); // 1ï¼å½æ°ç 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 (*) proxy å°âè·å 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) |
[[Delete]] |
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"
è¿éï¼
Reflect.get读åä¸ä¸ªå¯¹è±¡å±æ§ãReflect.setåå ¥ä¸ä¸ªå¯¹è±¡å±æ§ï¼å¦æåå ¥æååè¿åtrueï¼å¦åè¿åfalseã
è¿æ ·ï¼ä¸åé½å¾ç®åï¼å¦æä¸ä¸ªææå¨æ³è¦å°è°ç¨è½¬åç»å¯¹è±¡ï¼ååªé使ç¨ç¸åçåæ°è°ç¨ Reflect.<method> 就足å¤äºã
å¨å¤§å¤æ°æ
åµä¸ï¼æä»¬å¯ä»¥ä¸ä½¿ç¨ Reflect 宿ç¸åçäºæ
ï¼ä¾å¦ï¼ç¨äºè¯»å屿§ç Reflect.get(target, prop, receiver) å¯ä»¥è¢«æ¿æ¢ä¸º target[prop]ã尽管æä¸äºç»å¾®çå·®å«ã
代çä¸ä¸ª getter
让æä»¬çä¸ä¸ªç¤ºä¾ï¼æ¥è¯´æä¸ºä»ä¹ Reflect.get æ´å¥½ãæ¤å¤ï¼æä»¬è¿å°çå°ä¸ºä»ä¹ get/set æç¬¬ä¸ä¸ªåæ° receiverï¼è䏿们ä¹å仿¥æ²¡æä½¿ç¨è¿å®ã
æä»¬æä¸ä¸ªå¸¦æ _name 屿§å getter ç对象 userã
è¿æ¯å¯¹ 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 ææå¨å¨è¿éæ¯âéæçâï¼å®è¿å忥ç屿§ï¼ä¸ä¼åä»»ä½å
¶ä»çäºãè¿å¯¹äºæä»¬ç示ä¾èè¨å°±è¶³å¤äºã
ä¸åä¼¼ä¹é½å¾å¥½ã使¯è®©æä»¬å°ç¤ºä¾åå¾ç¨å¾®å¤æä¸ç¹ã
å¦ä¸ä¸ªå¯¹è±¡ admin ä» user ç»§æ¿åï¼æä»¬å¯ä»¥è§å¯å°é误çè¡ä¸ºï¼
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 åºè¯¥è¿å "Admin"ï¼è䏿¯ "Guest"ï¼
åçäºä»ä¹ï¼æè®¸æä»¬å¨ç»§æ¿æ¹é¢åéäºä»ä¹ï¼
使¯ï¼å¦ææä»¬ç§»é¤ä»£çï¼é£ä¹ä¸åé½ä¼æé¢æè¿è¡ã
é®é¢å®é
ä¸åºå¨ä»£çä¸ï¼å¨ (*) è¡ã
-
å½æä»¬è¯»å
admin.nameæ¶ï¼ç±äºadmin对象èªèº«æ²¡æå¯¹åºç屿§ï¼æç´¢å°è½¬å°å ¶ååã -
å忝
userProxyã -
ä»ä»£ç读å
name屿§æ¶ï¼getææå¨ä¼è¢«è§¦åï¼å¹¶ä»åå§å¯¹è±¡è¿åtarget[prop]屿§ï¼å¨(*)è¡ãå½è°ç¨
target[prop]æ¶ï¼è¥propæ¯ä¸ä¸ª getterï¼å®å°å¨this=targetä¸ä¸æä¸è¿è¡å ¶ä»£ç ãå æ¤ï¼ç»ææ¯æ¥èªåå§å¯¹è±¡targetçthis._nameï¼å³æ¥èªuserã
为äºè§£å³è¿ç§æ
åµï¼æä»¬éè¦ get ææå¨ç第ä¸ä¸ªåæ° receiverãå®ä¿è¯å°æ£ç¡®ç this ä¼ éç» getterã卿们çä¾å䏿¯ adminã
å¦ä½æä¸ä¸æä¼ éç» getterï¼å¯¹äºä¸ä¸ªå¸¸è§å½æ°ï¼æä»¬å¯ä»¥ä½¿ç¨ call/applyï¼ä½è¿æ¯ä¸ä¸ª getterï¼å®ä¸è½â被è°ç¨âï¼åªè½è¢«è®¿é®ã
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
ç°å¨ receiver ä¿çäºå¯¹æ£ç¡® this çå¼ç¨ï¼å³ adminï¼ï¼è¯¥å¼ç¨æ¯å¨ (*) è¡ä¸è¢«éè¿ Reflect.get ä¼ éç» getter çã
æä»¬å¯ä»¥æææå¨éå徿´çï¼
get(target, prop, receiver) {
return Reflect.get(...arguments);
}
Reflect è°ç¨çå½å䏿æå¨çå½åå®å
¨ç¸åï¼å¹¶ä¸æ¥åç¸åçåæ°ãå®ä»¬æ¯ä»¥è¿ç§æ¹å¼ä¸é¨è®¾è®¡çã
å æ¤ï¼return Reflect... æä¾äºä¸ä¸ªå®å
¨çæ¹å¼ï¼å¯ä»¥è½»æ¾å°è½¬åæä½ï¼å¹¶ç¡®ä¿æä»¬ä¸ä¼å¿è®°ä¸æ¤ç¸å
³çä»»ä½å
容ã
Proxy çå±éæ§
代çæä¾äºä¸ç§ç¬ç¹çæ¹æ³ï¼å¯ä»¥å¨æåºå±æ´æ¹æè°æ´ç°æå¯¹è±¡çè¡ä¸ºã使¯ï¼å®å¹¶ä¸å®ç¾ãæå±éæ§ã
å 建对象ï¼å é¨ææ§½ï¼Internal slotï¼
许å¤å
建对象ï¼ä¾å¦ Mapï¼Setï¼Dateï¼Promise çï¼é½ä½¿ç¨äºæè°çâå
é¨ææ§½âã
å®ä»¬ç±»ä¼¼äºå±æ§ï¼ä½ä»
éäºå
é¨ä½¿ç¨ï¼ä»
ç¨äºè§èç®çãä¾å¦ï¼Map å°é¡¹ç®ï¼itemï¼åå¨å¨ [[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ï¼å·¥ä½äºï¼ï¼
ç°å¨å®æ£å¸¸å·¥ä½äºï¼å 为 get ææå¨å°å½æ°å±æ§ï¼ä¾å¦ map.setï¼ç»å®å°äºç®æ 对象ï¼mapï¼æ¬èº«ã
ä¸åé¢ç示ä¾ä¸åï¼proxy.set(...) å
é¨ this çå¼å¹¶ä¸æ¯ proxyï¼èæ¯åå§ç mapãå æ¤ï¼å½set ææå¨çå
é¨å®ç°å°è¯è®¿é® this.[[MapData]] å
é¨ææ§½æ¶ï¼å®ä¼æåã
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ï¼å®æ²¡æå¸¦æç§æåæ®µçææ§½ã
忬¡ï¼å¸¦æ bind æ¹æ³çè§£å³æ¹æ¡ä½¿å®æ¢å¤æ£å¸¸ï¼
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
代çååå§å¯¹è±¡æ¯ä¸åç对象ãè¿å¾èªç¶ï¼å¯¹å§ï¼
æä»¥ï¼å¦ææä»¬ä½¿ç¨åå§å¯¹è±¡ä½ä¸ºé®ï¼ç¶åå¯¹å ¶è¿è¡ä»£çï¼ä¹åå´æ æ³æ¾å°ä»£çäºï¼
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ï¼å ä¸ºä»£çæ¯ä¸ä¸ªä¸åç对象ã
===Proxy å¯ä»¥æ¦æªè®¸å¤æä½ç¬¦ï¼ä¾å¦ newï¼ä½¿ç¨ constructï¼ï¼inï¼ä½¿ç¨ hasï¼ï¼deleteï¼ä½¿ç¨ deletePropertyï¼çã
使¯æ²¡æåæ³æ¦æªå¯¹äºå¯¹è±¡çä¸¥æ ¼ç¸çæ§æ£æ¥ãä¸ä¸ªå¯¹è±¡åªä¸¥æ ¼çäºå ¶èªèº«ï¼æ²¡æå ¶ä»å¼ã
å æ¤ï¼æ¯è¾å¯¹è±¡æ¯å¦ç¸ççæææä½åå 建类é½ä¼åºå对象å代çãè¿é没æéæçæ¿ä»£åã
坿¤é Proxy
ä¸ä¸ª 坿¤é çä»£çæ¯å¯ä»¥è¢«ç¦ç¨ç代çã
å设æä»¬æä¸ä¸ªèµæºï¼å¹¶ä¸æ³éæ¶å ³éå¯¹è¯¥èµæºç访é®ã
æä»¬å¯ä»¥åçæ¯å°å®å è£ æä¸ä¸ªå¯æ¤éç代çï¼æ²¡æä»»ä½ææå¨ãè¿æ ·ç代çä¼å°æä½è½¬åç»å¯¹è±¡ï¼å¹¶ä¸æä»¬å¯ä»¥éæ¶å°å ¶ç¦ç¨ã
è¯æ³ä¸ºï¼
let {proxy, revoke} = Proxy.revocable(target, handler)
该è°ç¨è¿åä¸ä¸ªå¸¦æ proxy å revoke 彿°ç对象以å°å
¶ç¦ç¨ã
è¿æ¯ä¸ä¸ªä¾åï¼
let object = {
data: "Valuable data"
};
let {proxy, revoke} = Proxy.revocable(object, {});
// å° proxy ä¼ éå°å
¶ä»æå¤ï¼è䏿¯å¯¹è±¡...
alert(proxy.data); // Valuable data
// ç¨åï¼å¨æä»¬ç代ç ä¸
revoke();
// proxy ä¸åå·¥ä½ï¼revokedï¼
alert(proxy.data); // Error
对 revoke() çè°ç¨ä¼ä»ä»£çä¸å é¤å¯¹ç®æ å¯¹è±¡çææå
é¨å¼ç¨ï¼å æ¤å®ä»¬ä¹é´åæ è¿æ¥ã
æåï¼revoke ä¸ proxy æ¯åå¼çï¼å æ¤æä»¬å¯ä»¥ä¼ é proxyï¼åæ¶å° revoke çå¨å½åèå´å
ã
æä»¬ä¹å¯ä»¥éè¿è®¾ç½® proxy.revoke = revoke æ¥å° revoke ç»å®å° proxyã
å¦ä¸ç§éæ©æ¯å建ä¸ä¸ª WeakMapï¼å
¶ä¸ proxy ä½ä¸ºé®ï¼ç¸åºç revoke ä½ä¸ºå¼ï¼è¿æ ·å¯ä»¥è½»æ¾æ¾å° proxy æå¯¹åºç revokeï¼
let revokes = new WeakMap();
let object = {
data: "Valuable data"
};
let {proxy, revoke} = Proxy.revocable(object, {});
revokes.set(proxy, revoke);
// ...æä»¬ä»£ç ä¸çå
¶ä»ä½ç½®...
revoke = revokes.get(proxy);
revoke();
alert(proxy.data); // Errorï¼revokedï¼
æ¤å¤æä»¬ä½¿ç¨ WeakMap è䏿¯ Mapï¼å 为å®ä¸ä¼é»æ¢åå¾åæ¶ã妿ä¸ä¸ªä»£ç对象åå¾âä¸å¯è®¿é®âï¼ä¾å¦ï¼æ²¡æåéåå¼ç¨å®ï¼ï¼å WeakMap å
许å°å
¶ä¸å®ç revoke ä¸èµ·ä»å
å䏿¸
é¤ï¼å 为æä»¬ä¸åéè¦å®äºã
åèèµæ
æ»ç»
Proxy æ¯å¯¹è±¡çå
è£
å¨ï¼å°ä»£çä¸çæä½è½¬åå°å¯¹è±¡ï¼å¹¶å¯ä»¥éæ©æè·å
¶ä¸ä¸äºæä½ã
å®å¯ä»¥å è£ ä»»ä½ç±»åç对象ï¼å æ¬ç±»å彿°ã
è¯æ³ä¸ºï¼
let proxy = new Proxy(target, {
/* trap */
});
â¦â¦ç¶åï¼æä»¬åºè¯¥å¨ææå°æ¹ä½¿ç¨ proxy è䏿¯ targetãä»£çæ²¡æèªå·±ç屿§ææ¹æ³ã妿æä¾äºææå¨ï¼trapï¼ï¼å®å°æè·æä½ï¼å¦åä¼å°å
¶è½¬åç» target 对象ã
æä»¬å¯ä»¥æè·ï¼
- 读åï¼
getï¼ï¼åå ¥ï¼setï¼ï¼å é¤ï¼deletePropertyï¼å±æ§ï¼çè³æ¯ä¸åå¨ç屿§ï¼ã - 彿°è°ç¨ï¼
applyææå¨ï¼ã newæä½ï¼constructææå¨ï¼ã- 许å¤å ¶ä»æä½ï¼å®æ´åè¡¨è¯·è§æ¬æå¼å¤´é¨åå docsï¼ã
è¿ä½¿æä»¬è½å¤å建âèæâ屿§åæ¹æ³ï¼å®ç°é»è®¤å¼ï¼å¯è§å¯å¯¹è±¡ï¼å½æ°è£ 饰å¨çã
æä»¬è¿å¯ä»¥å°å¯¹è±¡å¤æ¬¡å è£ å¨ä¸åç代çä¸ï¼å¹¶ç¨å¤ä¸ªå个æ¹é¢çåè½å¯¹å ¶è¿è¡è£ 饰ã
Reflect API æ¨å¨è¡¥å
Proxyã对äºä»»æ Proxy ææå¨ï¼é½æä¸ä¸ªå¸¦æç¸ååæ°ç Reflect è°ç¨ãæä»¬åºè¯¥ä½¿ç¨å®ä»¬å°è°ç¨è½¬åç»ç®æ 对象ã
Proxy æä¸äºå±éæ§ï¼
- å å»ºå¯¹è±¡å ·æâå é¨ææ§½âï¼å¯¹è¿äºå¯¹è±¡çè®¿é®æ æ³è¢«ä»£çã请åé 䏿ä¸çè§£å³æ¹æ³ã
- ç§æç±»åæ®µä¹æ¯å¦æ¤ï¼å 为å®ä»¬ä¹æ¯å¨å
é¨ä½¿ç¨ææ§½å®ç°çãå æ¤ï¼ä»£çæ¹æ³çè°ç¨å¿
é¡»å
·æç®æ 对象ä½ä¸º
thisæè½è®¿é®å®ä»¬ã - 对象çä¸¥æ ¼ç¸çæ§æ£æ¥
===æ æ³è¢«æ¦æªã - æ§è½ï¼åºåæµè¯ï¼benchmarkï¼åå³äºå¼æï¼ä½éå¸¸ä½¿ç¨æç®åç代ç访é®å±æ§æéçæ¶é´ä¹è¦é¿å åãå®é ä¸ï¼è¿ä» 对æäºâç¶é¢â对象æ¥è¯´æéè¦ã
è¯è®º
<code>æ ç¾æå ¥åªæå 个è¯ç代ç ï¼æå ¥å¤è¡ä»£ç å¯ä»¥ä½¿ç¨<pre>æ ç¾ï¼å¯¹äºè¶ è¿ 10 è¡ç代ç ï¼å»ºè®®ä½ ä½¿ç¨æ²ç®±ï¼plnkrï¼JSBinï¼codepenâ¦ï¼