JavaScript å¨å¤ç彿°æ¶æä¾äºéå¡ççµæ´»æ§ãå®ä»¬å¯ä»¥è¢«ä¼ éï¼ç¨ä½å¯¹è±¡ï¼ç°å¨æä»¬å°çå°å¦ä½å¨å®ä»¬ä¹é´ 转åï¼forwardï¼ è°ç¨å¹¶ è£ é¥°ï¼decorateï¼ å®ä»¬ã
éæç¼å
å设æä»¬æä¸ä¸ª CPU éè´è½½ç彿° slow(x)ï¼ä½å®çç»ææ¯ç¨³å®çãæ¢å¥è¯è¯´ï¼å¯¹äºç¸åç xï¼å®æ»æ¯è¿åç¸åçç»æã
妿ç»å¸¸è°ç¨è¯¥å½æ°ï¼æä»¬å¯è½å¸æå°ç»æç¼åï¼è®°ä½ï¼ä¸æ¥ï¼ä»¥é¿å å¨éæ°è®¡ç®ä¸è±è´¹é¢å¤çæ¶é´ã
使¯æä»¬ä¸æ¯å°è¿ä¸ªåè½æ·»å å° slow() ä¸ï¼èæ¯å建ä¸ä¸ªå
è£
å¨ï¼wrapperï¼å½æ°ï¼è¯¥å½æ°å¢å äºç¼ååè½ãæ£å¦æä»¬å°è¦çå°çï¼è¿æ ·åæå¾å¤å¥½å¤ã
ä¸é¢æ¯ä»£ç åè§£éï¼
function slow(x) {
// è¿éå¯è½ä¼æéè´è½½ç CPU å¯éåå·¥ä½
alert(`Called with ${x}`);
return x;
}
function cachingDecorator(func) {
let cache = new Map();
return function(x) {
if (cache.has(x)) { // 妿ç¼å䏿坹åºçç»æ
return cache.get(x); // ä»ç¼åä¸è¯»åç»æ
}
let result = func(x); // å¦åå°±è°ç¨ func
cache.set(x, result); // ç¶åå°ç»æç¼åï¼è®°ä½ï¼ä¸æ¥
return result;
};
}
slow = cachingDecorator(slow);
alert( slow(1) ); // slow(1) 被ç¼å䏿¥äºï¼å¹¶è¿åç»æ
alert( "Again: " + slow(1) ); // è¿åç¼åä¸ç slow(1) çç»æ
alert( slow(2) ); // slow(2) 被ç¼å䏿¥äºï¼å¹¶è¿åç»æ
alert( "Again: " + slow(2) ); // è¿åç¼åä¸ç slow(2) çç»æ
å¨ä¸é¢ç代ç ä¸ï¼cachingDecorator æ¯ä¸ä¸ª è£
饰å¨ï¼decoratorï¼ï¼ä¸ä¸ªç¹æ®ç彿°ï¼å®æ¥åå¦ä¸ä¸ªå½æ°å¹¶æ¹åå®çè¡ä¸ºã
å
¶ææ³æ¯ï¼æä»¬å¯ä»¥ä¸ºä»»ä½å½æ°è°ç¨ cachingDecoratorï¼å®å°è¿åç¼åå
è£
å¨ãè¿å¾æ£åï¼å 为æä»¬æå¾å¤å½æ°å¯ä»¥ä½¿ç¨è¿æ ·çç¹æ§ï¼èæä»¬éè¦åçå°±æ¯å° cachingDecorator åºç¨äºå®ä»¬ã
éè¿å°ç¼åä¸ä¸»å½æ°ä»£ç åå¼ï¼æä»¬è¿å¯ä»¥ä½¿ä¸»å½æ°ä»£ç å徿´ç®åã
cachingDecorator(func) çç»ææ¯ä¸ä¸ªâå
è£
å¨âï¼function(x) å° func(x) çè°ç¨âå
è£
âå°ç¼åé»è¾ä¸ï¼
ä»å¤é¨ä»£ç æ¥çï¼å
è£
ç slow 彿°æ§è¡çä»ç¶æ¯ä¸ä¹åç¸åçæä½ãå®åªæ¯å¨å
¶è¡ä¸ºä¸æ·»å äºç¼ååè½ã
æ»èè¨ä¹ï¼ä½¿ç¨å离ç cachingDecorator è䏿¯æ¹å slow æ¬èº«çä»£ç æå 个好å¤ï¼
cachingDecoratoræ¯å¯éç¨çãæä»¬å¯ä»¥å°å®åºç¨äºå¦ä¸ä¸ªå½æ°ã- ç¼åé»è¾æ¯ç¬ç«çï¼å®æ²¡æå¢å
slowæ¬èº«ç夿æ§ï¼å¦ææçè¯ï¼ã - 妿éè¦ï¼æä»¬å¯ä»¥ç»åå¤ä¸ªè£ 饰å¨ï¼å ¶ä»è£ 饰å¨å°éµå¾ªåæ ·çé»è¾ï¼ã
ä½¿ç¨ âfunc.callâ 设å®ä¸ä¸æ
ä¸é¢æå°çç¼åè£ é¥°å¨ä¸éç¨äºå¯¹è±¡æ¹æ³ã
ä¾å¦ï¼å¨ä¸é¢ç代ç ä¸ï¼worker.slow() å¨è£
饰å忢工ä½ï¼
// æä»¬å°å¯¹ worker.slow çç»æè¿è¡ç¼å
let worker = {
someMethod() {
return 1;
},
slow(x) {
// 坿ç CPU è¿è½½ä»»å¡
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
};
// åä¹åä¾åä¸ç代ç ç¸å
function cachingDecorator(func) {
let cache = new Map();
return function(x) {
if (cache.has(x)) {
return cache.get(x);
}
let result = func(x); // (**)
cache.set(x, result);
return result;
};
}
alert( worker.slow(1) ); // åå§æ¹æ³ææ
worker.slow = cachingDecorator(worker.slow); // ç°å¨å¯¹å
¶è¿è¡ç¼å
alert( worker.slow(2) ); // è¤ï¼Error: Cannot read property 'someMethod' of undefined
é误åçå¨è¯å¾è®¿é® this.someMethod 并失败äºç (*) è¡ä¸ãä½ è½çåºæ¥ä¸ºä»ä¹åï¼
åå æ¯å
è£
å¨å°åå§å½æ°è°ç¨ä¸º (**) è¡ä¸ç func(x)ãå¹¶ä¸ï¼å½è¿æ ·è°ç¨æ¶ï¼å½æ°å°å¾å° this = undefinedã
妿å°è¯è¿è¡ä¸é¢è¿æ®µä»£ç ï¼æä»¬ä¼è§å¯å°ç±»ä¼¼çé®é¢ï¼
let func = worker.slow;
func(2);
å æ¤ï¼å
è£
å¨å°è°ç¨ä¼ éç»åå§æ¹æ³ï¼ä½æ²¡æä¸ä¸æ thisãå æ¤ï¼åçäºé误ã
让æä»¬æ¥è§£å³è¿ä¸ªé®é¢ã
æä¸ä¸ªç¹æ®çå
å»ºå½æ°æ¹æ³ func.call(context, â¦args)ï¼å®å
许è°ç¨ä¸ä¸ªæ¾å¼è®¾ç½® this ç彿°ã
è¯æ³å¦ä¸ï¼
func.call(context, arg1, arg2, ...)
å®è¿è¡ funcï¼æä¾ç第ä¸ä¸ªåæ°ä½ä¸º thisï¼åé¢çä½ä¸ºåæ°ï¼argumentsï¼ã
ç®åå°è¯´ï¼è¿ä¸¤ä¸ªè°ç¨å ä¹ç¸åï¼
func(1, 2, 3);
func.call(obj, 1, 2, 3)
å®ä»¬è°ç¨ç齿¯ funcï¼åæ°æ¯ 1ã2 å 3ãå¯ä¸çåºå«æ¯ func.call è¿ä¼å° this 设置为 objã
ä¾å¦ï¼å¨ä¸é¢ç代ç ä¸ï¼æä»¬å¨ä¸å对象çä¸ä¸æä¸è°ç¨ sayHiï¼sayHi.call(user) è¿è¡ sayHi å¹¶æä¾äº this=userï¼ç¶åä¸ä¸è¡è®¾ç½® this=adminï¼
function sayHi() {
alert(this.name);
}
let user = { name: "John" };
let admin = { name: "Admin" };
// ä½¿ç¨ call å°ä¸åçå¯¹è±¡ä¼ é为 "this"
sayHi.call( user ); // John
sayHi.call( admin ); // Admin
å¨è¿éæä»¬ç¨å¸¦æç»å®ä¸ä¸æå phrase ç call è°ç¨ sayï¼
function say(phrase) {
alert(this.name + ': ' + phrase);
}
let user = { name: "John" };
// user æä¸º thisï¼"Hello" æä¸ºç¬¬ä¸ä¸ªåæ°
say.call( user, "Hello" ); // John: Hello
卿们çä¾åä¸ï¼æä»¬å¯ä»¥å¨å
è£
å¨ä¸ä½¿ç¨ call å°ä¸ä¸æä¼ éç»åå§å½æ°ï¼
let worker = {
someMethod() {
return 1;
},
slow(x) {
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
};
function cachingDecorator(func) {
let cache = new Map();
return function(x) {
if (cache.has(x)) {
return cache.get(x);
}
let result = func.call(this, x); // ç°å¨ "this" 被æ£ç¡®å°ä¼ éäº
cache.set(x, result);
return result;
};
}
worker.slow = cachingDecorator(worker.slow); // ç°å¨å¯¹å
¶è¿è¡ç¼å
alert( worker.slow(2) ); // 工使£å¸¸
alert( worker.slow(2) ); // 工使£å¸¸ï¼æ²¡æè°ç¨åå§å½æ°ï¼ä½¿ç¨çç¼åï¼
ç°å¨ä¸å齿£å¸¸å·¥ä½äºã
为äºè®©å¤§å®¶çè§£å°æ´æ¸
æ°ä¸äºï¼è®©æä»¬æ´æ·±å
¥å°çç this æ¯å¦ä½è¢«ä¼ éçï¼
- å¨ç»è¿è£
饰ä¹åï¼
worker.slowç°å¨æ¯å è£ å¨function (x) { ... }ã - å æ¤ï¼å½
worker.slow(2)æ§è¡æ¶ï¼å è£ å¨å°2ä½ä¸ºåæ°ï¼å¹¶ä¸this=workerï¼å®æ¯ç¹ç¬¦å·.ä¹åç对象ï¼ã - å¨å
è£
å¨å
é¨ï¼åè®¾ç»æå°æªç¼åï¼
func.call(this, x)å°å½åçthisï¼=workerï¼åå½åçåæ°ï¼=2ï¼ä¼ éç»åå§æ¹æ³ã
ä¼ éå¤ä¸ªåæ°
ç°å¨è®©æä»¬æ cachingDecorator å徿´å éç¨ãå°ç°å¨ä¸ºæ¢ï¼å®åªè½ç¨äºå忰彿°ã
ç°å¨å¦ä½ç¼åå¤åæ° worker.slow æ¹æ³å¢ï¼
let worker = {
slow(min, max) {
return min + max; // scary CPU-hogger is assumed
}
};
// åºè¯¥è®°ä½ç¸ååæ°çè°ç¨
worker.slow = cachingDecorator(worker.slow);
ä¹åï¼å¯¹äºåä¸ªåæ° xï¼æä»¬å¯ä»¥åªä½¿ç¨ cache.set(x, result) æ¥ä¿åç»æï¼å¹¶ä½¿ç¨ cache.get(x) æ¥æ£ç´¢å¹¶è·åç»æã使¯ç°å¨ï¼æä»¬éè¦è®°ä½ åæ°ç»å (min,max) çç»æãåçç Map ä»
å°å个å¼ä½ä¸ºé®ï¼keyï¼ã
è¿å¿æè®¸å¤è§£å³æ¹æ¡å¯ä»¥å®ç°ï¼
- å®ç°ä¸ä¸ªæ°çï¼æä½¿ç¨ç¬¬ä¸æ¹çï¼ç±»ä¼¼ map çæ´éç¨å¹¶ä¸å 许å¤ä¸ªé®çæ°æ®ç»æã
- 使ç¨åµå¥ mapï¼
cache.set(min)å°æ¯ä¸ä¸ªåå¨ï¼é®å¼ï¼å¯¹(max, result)çMapãæä»¥æä»¬å¯ä»¥ä½¿ç¨cache.get(min).get(max)æ¥è·åresultã - å°ä¸¤ä¸ªå¼å并为ä¸ä¸ªã为äºçµæ´»æ§ï¼æä»¬å¯ä»¥å è®¸ä¸ºè£ é¥°å¨æä¾ä¸ä¸ªâåå¸å½æ°âï¼è¯¥å½æ°ç¥éå¦ä½å°å¤ä¸ªå¼å并为ä¸ä¸ªå¼ã
对äºè®¸å¤å®é åºç¨ï¼ç¬¬ä¸ç§æ¹å¼å°±è¶³å¤äºï¼æä»¥æä»¬å°±ç¨è¿ä¸ªå§ã
å½ç¶ï¼æä»¬éè¦ä¼ å
¥çä¸ä»
æ¯ xï¼è¿éè¦ä¼ å
¥ func.call çææåæ°ã让æä»¬åæ³ä¸ä¸ï¼å¨ function() 䏿们å¯ä»¥å¾å°ä¸ä¸ªå
嫿æåæ°ç伪æ°ç»ï¼pseudo-arrayï¼argumentsï¼é£ä¹ func.call(this, x) åºè¯¥è¢«æ¿æ¢ä¸º func.call(this, ...arguments)ã
è¿æ¯ä¸ä¸ªæ´å¼ºå¤§ç cachingDecoratorï¼
let worker = {
slow(min, max) {
alert(`Called with ${min},${max}`);
return min + max;
}
};
function cachingDecorator(func, hash) {
let cache = new Map();
return function() {
let key = hash(arguments); // (*)
if (cache.has(key)) {
return cache.get(key);
}
let result = func.call(this, ...arguments); // (**)
cache.set(key, result);
return result;
};
}
function hash(args) {
return args[0] + ',' + args[1];
}
worker.slow = cachingDecorator(worker.slow, hash);
alert( worker.slow(3, 5) ); // works
alert( "Again " + worker.slow(3, 5) ); // same (cached)
ç°å¨è¿ä¸ªå è£ å¨å¯ä»¥å¤çä»»ææ°éçåæ°äºï¼å°½ç®¡åå¸å½æ°è¿éè¦è¢«è¿è¡è°æ´ä»¥å è®¸ä»»ææ°éçåæ°ãä¸ç§æè¶£çå¤çæ¹æ³å°å¨ä¸é¢è®²å°ï¼ã
è¿éæä¸¤ä¸ªååï¼
- å¨
(*)è¡ä¸å®è°ç¨hashæ¥ä»argumentså建ä¸ä¸ªåç¬çé®ãè¿éæä»¬ä½¿ç¨ä¸ä¸ªç®åçâè¿æ¥â彿°ï¼å°åæ°(3, 5)转æ¢ä¸ºé®"3,5"ãæ´å¤æçæ åµå¯è½éè¦å ¶ä»åå¸å½æ°ã - ç¶å
(**)è¡ä½¿ç¨func.call(this, ...arguments)å°å è£ å¨è·å¾çä¸ä¸æåææåæ°ï¼ä¸ä» ä» æ¯ç¬¬ä¸ä¸ªåæ°ï¼ä¼ éç»åå§å½æ°ã
func.apply
æä»¬å¯ä»¥ä½¿ç¨ func.apply(this, arguments) ä»£æ¿ func.call(this, ...arguments)ã
å å»ºæ¹æ³ func.apply çè¯æ³æ¯ï¼
func.apply(context, args)
å®è¿è¡ func 设置 this=contextï¼å¹¶ä½¿ç¨ç±»æ°ç»å¯¹è±¡ args ä½ä¸ºåæ°å表ï¼argumentsï¼ã
call å apply ä¹é´å¯ä¸çè¯æ³åºå«æ¯ï¼call ææä¸ä¸ªåæ°å表ï¼è apply ææä¸ä¸ªå
å«è¿äºåæ°çç±»æ°ç»å¯¹è±¡ã
å æ¤ï¼è¿ä¸¤ä¸ªè°ç¨å 乿¯çæçï¼
func.call(context, ...args);
func.apply(context, args);
å®ä»¬ä½¿ç¨ç»å®çä¸ä¸æååæ°æ§è¡ç¸åç func è°ç¨ã
åªæä¸ä¸ªå
³äº args çç»å¾®çå·®å«ï¼
- Spread è¯æ³
...å è®¸å° å¯è¿ä»£å¯¹è±¡argsä½ä¸ºåè¡¨ä¼ éç»callã applyåªæ¥å ç±»æ°ç»argsã
â¦â¦å¯¹äºå³å¯è¿ä»£åæ¯ç±»æ°ç»ç对象ï¼ä¾å¦ä¸ä¸ªçæ£çæ°ç»ï¼æä»¬ä½¿ç¨ call æ apply åå¯ï¼ä½æ¯ apply å¯è½ä¼æ´å¿«ï¼å ä¸ºå¤§å¤æ° JavaScript 弿å¨å
é¨å¯¹å
¶è¿è¡äºä¼åã
å°ææåæ°è¿åä¸ä¸æä¸èµ·ä¼ éç»å¦ä¸ä¸ªå½æ°è¢«ç§°ä¸ºâå¼å«è½¬ç§»ï¼call forwardingï¼âã
è¿æ¯å®çæç®å½¢å¼ï¼
let wrapper = function() {
return func.apply(this, arguments);
};
å½å¤é¨ä»£ç è°ç¨è¿ç§å
è£
å¨ wrapper æ¶ï¼å®ä¸åå§å½æ° func çè°ç¨æ¯æ æ³åºåçã
åç¨ä¸ç§æ¹æ³
ç°å¨ï¼è®©æä»¬å¯¹åå¸å½æ°ååä¸ä¸ªè¾å°çæ¹è¿ï¼
function hash(args) {
return args[0] + ',' + args[1];
}
æªè³ç®åï¼å®ä»
éç¨äºä¸¤ä¸ªåæ°ã妿å®å¯ä»¥éç¨äºä»»ä½æ°éç args å°±æ´å¥½äºã
èªç¶çè§£å³æ¹æ¡æ¯ä½¿ç¨ arr.join æ¹æ³ï¼
function hash(args) {
return args.join();
}
â¦â¦ä¸å¹¸çæ¯ï¼è¿ä¸è¡ãå 为æä»¬æ£å¨è°ç¨ hash(arguments)ï¼arguments å¯¹è±¡æ¢æ¯å¯è¿ä»£å¯¹è±¡åæ¯ç±»æ°ç»å¯¹è±¡ï¼ä½å®å¹¶ä¸æ¯çæ£çæ°ç»ã
æä»¥å¨å®ä¸é¢è°ç¨ join ä¼å¤±è´¥ï¼æä»¬å¯ä»¥å¨ä¸é¢çå°ï¼
function hash() {
alert( arguments.join() ); // Error: arguments.join is not a function
}
hash(1, 2);
ä¸è¿ï¼æä¸ç§ç®åçæ¹æ³å¯ä»¥ä½¿ç¨æ°ç»ç join æ¹æ³ï¼
function hash() {
alert( [].join.call(arguments) ); // 1,2
}
hash(1, 2);
è¿ä¸ªæå·§è¢«ç§°ä¸º æ¹æ³åç¨ï¼method borrowingï¼ã
æä»¬ä»å¸¸è§æ°ç» [].join ä¸è·åï¼åç¨ï¼join æ¹æ³ï¼å¹¶ä½¿ç¨ [].join.call å¨ arguments çä¸ä¸æä¸è¿è¡å®ã
å®ä¸ºä»ä¹ææï¼
飿¯å 为åçæ¹æ³ arr.join(glue) çå
é¨ç®æ³é常ç®åã
ä»è§èä¸å ä¹âæåæ ·âè§£éå¦ä¸ï¼
- 让
glueæä¸ºç¬¬ä¸ä¸ªåæ°ï¼å¦ææ²¡æåæ°ï¼å使ç¨éå·","ã - 让
result为空å符串ã - å°
this[0]éå å°resultã - éå
glueåthis[1]ã - éå
glueåthis[2]ã - â¦â¦ä»¥æ¤ç±»æ¨ï¼ç´å°
this.length项ç®è¢«ç²å¨ä¸èµ·ã - è¿å
resultã
å æ¤ï¼ä»ææ¯ä¸è®²ï¼å®éè¦ this å¹¶å° this[0]ï¼this[1] â¦â¦ç join å¨ä¸èµ·ãå®çç¼åæ¹å¼æ¯æ
æå
许任ä½ç±»æ°ç»ç this çï¼ä¸æ¯å·§åï¼å¾å¤æ¹æ³é½éµå¾ªè¿ç§åæ³ï¼ãè¿å°±æ¯ä¸ºä»ä¹å®ä¹å¯ä»¥å this=arguments ä¸èµ·ä½¿ç¨ã
è£ é¥°å¨å彿°å±æ§
é常ï¼ç¨è£
饰ç彿°æ¿æ¢ä¸ä¸ªå½æ°æä¸ä¸ªæ¹æ³æ¯å®å
¨çï¼é¤äºä¸ä»¶å°ä¸è¥¿ã妿åå§å½æ°æå±æ§ï¼ä¾å¦ func.calledCount æå
¶ä»ï¼åè£
饰åç彿°å°ä¸åæä¾è¿äºå±æ§ãå ä¸ºè¿æ¯è£
饰å¨ãå æ¤ï¼å¦ææäººä½¿ç¨å®ä»¬ï¼é£ä¹å°±éè¦å°å¿ã
ä¾å¦ï¼å¨ä¸é¢ç示ä¾ä¸ï¼å¦æ slow 彿°å
·æä»»ä½å±æ§ï¼è cachingDecorator(slow) 忝ä¸ä¸ªæ²¡æè¿äºå±æ§çå
è£
å¨ã
ä¸äºå è£ å¨å¯è½ä¼æä¾èªå·±ç屿§ãä¾å¦ï¼è£ 饰å¨ä¼è®¡ç®ä¸ä¸ªå½æ°è¢«è°ç¨äºå¤å°æ¬¡ä»¥åè±è´¹äºå¤å°æ¶é´ï¼å¹¶éè¿å è£ å¨å±æ§å ¬å¼ï¼exposeï¼è¿äºä¿¡æ¯ã
åå¨ä¸ç§å建è£
饰å¨çæ¹æ³ï¼è¯¥è£
饰å¨å¯ä¿ç坹彿°å±æ§çè®¿é®æéï¼ä½è¿éè¦ä½¿ç¨ç¹æ®ç Proxy 对象æ¥å
è£
彿°ãæä»¬å°å¨åé¢ç Proxy å Reflect ä¸å¦ä¹ å®ã
æ»ç»
è£ é¥°å¨ æ¯ä¸ä¸ªå´ç»æ¹å彿°è¡ä¸ºçå è£ å¨ã主è¦å·¥ä½ä»ç±è¯¥å½æ°æ¥å®æã
è£ é¥°å¨å¯ä»¥è¢«ç使¯å¯ä»¥æ·»å å°å½æ°ç âfeaturesâ æ âaspectsâãæä»¬å¯ä»¥æ·»å ä¸ä¸ªææ·»å å¤ä¸ªãèè¿ä¸å齿 éæ´æ¹å ¶ä»£ç ï¼
为äºå®ç° cachingDecoratorï¼æä»¬ç ç©¶äºä»¥ä¸æ¹æ³ï¼
- func.call(context, arg1, arg2â¦) ââ ç¨ç»å®çä¸ä¸æååæ°è°ç¨
funcã - func.apply(context, args) ââ è°ç¨
funcå°contextä½ä¸ºthisåç±»æ°ç»çargsä¼ éç»åæ°å表ã
éç¨ç è°ç¨ä¼ éï¼call forwardingï¼ é常æ¯ä½¿ç¨ apply 宿çï¼
let wrapper = function() {
return original.apply(this, arguments);
};
æä»¬ä¹å¯ä»¥çå°ä¸ä¸ª æ¹æ³åç¨ï¼method borrowingï¼ çä¾åï¼å°±æ¯æä»¬ä»ä¸ä¸ªå¯¹è±¡ä¸è·åä¸ä¸ªæ¹æ³ï¼å¹¶å¨å¦ä¸ä¸ªå¯¹è±¡çä¸ä¸æä¸âè°ç¨âå®ãéç¨æ°ç»æ¹æ³å¹¶å°å®ä»¬åºç¨äºåæ° arguments æ¯å¾å¸¸è§çãå¦ä¸ç§æ¹æ³æ¯ä½¿ç¨ Rest åæ°å¯¹è±¡ï¼è¯¥å¯¹è±¡æ¯ä¸ä¸ªçæ£çæ°ç»ã
å¨ JavaScript é¢åéæå¾å¤è£ 饰å¨ï¼decoratorsï¼ãéè¿è§£å³æ¬ç« çä»»å¡ï¼æ¥æ£æ¥ä½ ææ¡å®ä»¬çç¨åº¦å§ã
è¯è®º
<code>æ ç¾æå ¥åªæå 个è¯ç代ç ï¼æå ¥å¤è¡ä»£ç å¯ä»¥ä½¿ç¨<pre>æ ç¾ï¼å¯¹äºè¶ è¿ 10 è¡ç代ç ï¼å»ºè®®ä½ ä½¿ç¨æ²ç®±ï¼plnkrï¼JSBinï¼codepenâ¦ï¼