裝飾器是一種特殊類型的聲明,它可以被附加到類聲明,方法, 訪問符,屬性或參數上。 裝飾器使用 @expression 這種形式,expression 求值後必須爲一個函數,它會在運行時被調用,被裝飾的聲明信息作爲參數傳入。html
注意:裝飾器是一項實驗性特性,在將來的版本中可能會發生改變。前端
在 TypeScript 中裝飾器還屬於實驗性語法,你必須在命令行或 tsconfig.json 裏啓用 experimentalDecorators 編譯器選項:es6
tsc --target ES5 --experimentalDecorators
複製代碼
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
複製代碼
針對類的修飾,會接受一個參數即類對象自己,下文經過對類添加靜態屬性實現。express
@testable
class Demo{}
function testable(target) {
target.isTestable=true
}
console.log(Demo.isTestable) // true
複製代碼
針對類方法修飾,函數會接收3個參數:json
// descriptor對象原來的值以下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
// target:在方法中的target指向類的prototype
function readonly(target,key,descriptor){
descriptor.writable=false
return descriptor
}
class Demo {
@readonly
print(){console.log(`a:${this.a}`)}
}
複製代碼
針對類屬性裝飾器,函數會接收2個參數:微信
function set(value: string) {
return function (target: any, propertyName: string) {
target[propertyName] = value;
}
}
class Demo {
@set("hello world") greeting: string;
}
console.log(new Demo().greeting);// hello world
複製代碼
多個修飾器的執行順序是由外向內進入;再由內向外執行。app
class Demo {
@log(1)
@log(2)
method(){}
}
function log(id){
console.log('id is ',id)
return (target,property,descriptor)=>console.log('executed',id)
}
// 控制檯輸出
// id is 1
// id is 2
// executed 2
// executed 1
複製代碼
本文用到的個小方法async
// 返回空對象
export const noop = () => { };
/** * 判斷對象類型 * @param [obj: any] 參數對象 * @returns String */
export function isType(obj) {
return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
}
複製代碼
/** * 用於捕獲Error * @tips 請注意,參數params中的回調函數不能使用箭頭函數,不然將會引發上下文變更 * @param [Object | Function] params 接收異常捕獲回調,非必選參數 * @param [params.callback] callback 默認接收Function類型的參數,或者接收 Object 對象中的callback方法 * @returns descriptor */
export const DRCatchError = (params: any = noop) => (target, key, descriptor) => {
const original = descriptor.value;
let errorHandler: any = null;
if (isType(params) === 'function') {
errorHandler = params;
} else if (isType(params) === 'object') {
errorHandler = params.callback;
}
descriptor.value = async function () {
try {
await original.apply(this, arguments);
} catch (error) {
let resp = (error && error.response) || {};
let errorData = resp.data || error.message;
if (typeof errorHandler === 'function') {
errorHandler.call(this, errorData);
} else {
console.error(error);
}
}
};
return descriptor;
};
複製代碼
/** * 用於操做方法防抖 * @param [wait: number] 延時ms * @param [immediate: boolean] 當即執行 * @returns descriptor */
export const DRDebounce = (wait: number, immediate: boolean = false) => (target, key, descriptor) => {
let timeout: any;
const original = descriptor.value;
descriptor.value = function () {
let later = () => {
timeout = null;
if (!immediate) {
original.apply(this, arguments);
}
};
let callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
original.apply(this, arguments);
}
};
return descriptor;
};
複製代碼
/** * 用於操做函數節流 * @param [delay: number] 延時ms */
export const DRThrottle = (delay: number) => (target, key, descriptor) => {
let last: any;
let deferTimer: any;
const original = descriptor.value;
descriptor.value = function() {
let now = +new Date();
if (last && now < last + delay) {
clearTimeout(deferTimer);
deferTimer = setTimeout(() => {
last = now;
original.apply(this, arguments);
}, delay);
}else {
last = now;
original.apply(this, arguments);
}
};
return descriptor;
};
複製代碼
微信公衆號:前端雜論函數