装饰器是一种特殊类型的声明,它可以被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @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;
};
复制代码
微信公众号:前端杂论函数