JS装饰器的介绍

装饰器的基本介绍

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上。
装饰器使用@expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入

装饰器分类

装饰器大体上分为:

  1. 方法装饰器
  2. 类装饰器
  3. 属性装饰器
  4. 参数装饰器
  5. 访问器装饰器(get & set)

装饰器的使用

/**
 * 方法装饰器:方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。 
它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义
 * @param target :对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
 * @param name :成员的名字
 * @param descriptor :成员的属性描述符。
 */
const functionDecorator = (target, name, descriptor) => {
    console.log('方法装饰器函数被调用');
    console.log('target:', target);
    console.log('name:', name);
    console.log('descriptor:', descriptor);
}

/**
 * 方法装饰器带参数1
 * @param level 接受的参数
 * @returns 
 */
const functionDecorator1 = (level) => {
    console.log('log函数被调用');
    return (target, name, descriptor) => {
        console.log('log函数返回装饰器函数被调用:', level);
        // 缓存之前的值
        const oldValue = descriptor.value;
        // 复写原来的老值
        descriptor.value = (...args) => {
            // 使用原来的函数调用
            return oldValue.apply(null, args)
        }
    }
}

/**
* 方法装饰器带参数2
* @param level 接受的参数
* @returns 
*/
const functionDecorator2 = (level) => {
    console.log('log2函数被调用');
    return (target, name, descriptor) => {
        console.log('log2函数返回装饰器函数被调用:', level);
        // 缓存之前的值
        const oldValue = descriptor.value;
        // 复写原来的老值
        descriptor.value = (...args) => {
            // 使用原来的函数调用
            return oldValue.apply(null, args)
        }
    }
}

/**
 * 类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。 
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
 * @param target 
 */
const classDecorator = (target) => {
    console.log('类装饰器函数被调用');
    console.log(`target: ${target}`);
}

/**
 * 类装饰器带参数
 * @param params 
 * @returns 
 */
const classDecorator1 = (...params) => (target) => {
    console.log(`接受的参数: ${params}`);
    console.log(`target: ${target}`);
}


/**
 * 参数装饰器:参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 
参数装饰器应用于类构造函数或方法声明。
参数装饰器不能用在声明文件(.d.ts),重载或其它外部上下文(比如declare的类)里。
 * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
 * @param propertyKey 成员的名字。
 * @param parameterIndex 参数在函数参数列表中的索引。
 */
function paramDecorator(target: Object, propertyKey: string | symbol, parameterIndex: number) {
    console.log('参数装饰器函数被调用');
    console.log(`target`, target);
    console.log(`propertyKey`, propertyKey);
    console.log(`parameterIndex`, parameterIndex);
}

/**
 * 属性装饰器
 * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
 * @param name 成员的名字。
 */
const propertyDecorator = (target, name) => {
    console.log('属性装饰器函数被调用');
    console.log('target:', target)
    console.log('name:', name)
}

/**
 * 访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 
 访问器装饰器应用于访问器的属性描述符并且可以用来监视,修改或替换一个访问器的定义。 
 访问器装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如declare的类)里。
 (TypeScript不允许同时装饰一个成员的get和set访问器。取而代之的是,一个成员的所有装饰的必须应用在文档顺序的第一个访问器上。这是因为,在装饰器应用于一个属性描述符时,它联合了get和set访问器,而不是分开声明的)
 * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
 * @param name 成员的名字。
 * @param descriptor 成员的属性描述符。
 */
const visitDecorator = (target, name, descriptor) => {
    console.log('访问装饰器函数被调用'); 
}

/**
 * 带参数的访问装饰器:用于改变属性访问器的默认行为
 * @param flag 
 * @returns 
 */
const visitDecorator1 =  (flag:boolean) => {
    return (target, name, descriptor) => {
        descriptor.configurable = flag;
    }
}

@classDecorator
class Maths {
    @propertyDecorator
    private _version: number

    constructor(version: number) {
        this._version = version;
    }

    @visitDecorator1(false)
    get version(){
        return this._version;
    }

    @functionDecorator
    add(@paramDecorator num1: number, @paramDecorator num2: number) {
        return num1 + num2
    }
}
const math = new Maths(1)
console.log(math.add(2, 3));
console.log(math.version);

运行结果

属性装饰器函数被调用
target: {}
name: _version
参数装饰器函数被调用
target {}
propertyKey add
parameterIndex 1
参数装饰器函数被调用
target {}
propertyKey add
parameterIndex 0
方法装饰器函数被调用
target: {}
name: add
descriptor: {
value: [Function: add],
writable: true,
enumerable: false,
configurable: true
}
类装饰器函数被调用
target: class Maths {
constructor(version) {
this._version = version;
}
get version() {
return this._version;
}
add(num1, num2) {
return num1 + num2;
}
}
5
1

环境配置

我们先准备一个TS的基本环境。创建一个新的文件夹。

  • npm i typescript --save-dev 安装ts依赖
  • npm i ts-node --save-dev一个在node中写ts的工具包
  • npx tsc --init 初始化一个ts项目
  • 打开"experimentalDecorators": true, 属性,因为装饰器属于一个实验性的属性
  • npx ts-node index.ts来编译执行写的ts文件

为了避免ts的类型检查也可以把"strict": false,设为false或者关闭该属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上生花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值