学习ts(十)装饰器

定义

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上,是一种在不改变原类和使用继承的情况下,动态的扩展对象功能。
装饰器使用@expression形式,其中expression必须评估为一个函数,该函数将在运行时调用,并带有有关装饰声明的信息。
前置操作

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true
  }
}

使用

类装饰

类装饰器会把Class A的构造函数传入你的watcher函数当做第一个参数

const watcher: ClassDecorator = (target) => {
    target.prototype.age = 18
    target.prototype.getName = ():string=>{
        return 'hello'
    }
}
@watcher
class A {
    constructor() {
       
    }
}
const a = new A()
console.log((a as any).age);  // 18
console.log((a as any).getName());  //hello

装饰器工厂

如果想要传递参数,使装饰器变成类似工厂函数,只需要在装饰器函数内部再返回一个函数即可。

const watcher = (name: string): ClassDecorator => {
    return (target) => {
        target.prototype.age = 18
        target.prototype.getName = (): string => {
            return name
        }
    }

}
@watcher('hello data')
class A {
    constructor() {

    }
}
const a = new A()
console.log((a as any).age); // 18
console.log((a as any).getName()); // hello data

装饰器组合

可以给一个类使用多个装饰器

const watcher = (name: string): ClassDecorator => {
    return (target) => {
        target.prototype.age = 18
        target.prototype.getName = (): string => {
            return name
        }
    }

}

const addAge = (age:number):ClassDecorator => {
    return (target) =>{
        target.prototype.addAge = (): number => {
            return age+1
        }
    }
}

@watcher('hello data')  @addAge(20)
class A {
    constructor() {

    }
}
const a = new A()
console.log((a as any).age);
console.log((a as any).getName());
console.log((a as any).addAge());

方法/属性装饰器

装饰器参数为:

  • target:对象的原型:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  • propertyKey:方法的名称
  • descriptor:方法的属性描述符
    这三个属性实际就是Object.defineProperty的三个参数,如果是类的属性,则没有传递第三个参数
const met: MethodDecorator = (...args) => {
    console.log(args)
}

class A {
    constructor() {

    }
    @met
    getName(): string {
        return 'hello'
    }
}

const xx = new A()

学习ts(十)装饰器_第1张图片

// 声明装饰器修饰方法/属性
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.writable = false;
};

function property(target: any, propertyKey: string) {
    // 修改属性
    target[propertyKey] = '11223'
}

class Person {
    @property
    name: string;
    constructor() {
    }

    @method
    say() {
        return 'instance method';
    }
}

const xmz = new Person();

// 修改实例方法say
xmz.say = () => {
    return '5566'   //由于 descriptor.writable = false; 所以此处修改不生效
}
console.log(xmz.name)
console.log(xmz.say())  // nstance method

参数装饰

装饰器参数为:

  • target:当前对象的原型
  • propertyKey:参数的名称
  • index:参数数组中的位置
const init: ParameterDecorator = (...args)=>{
    console.log(args)
}
class A {
    constructor() {

    }
    getName(@init name: string = 'hello') {
        console.log(name) // [ {}, 'getName', 0 ]
    }
}

元数据

import data from './data.json'
import 'reflect-metadata'


const Base = (base: string) => {
    return (target) => {
        target.prototype.base = base
    }
}

const GetData = (url: string) => {
    console.log('getData run')
    const fn: MethodDecorator = (target: any, key, descriptor: PropertyDescriptor) => {
        const prop = Reflect.getMetadata('key', target)
        console.log(prop, 'prop')
        descriptor.value(prop ? data[prop] : data)
    }
    return fn;
}

const Result = () => {
    console.log('result run')
    const fn: ParameterDecorator = (target: any, key, index) => {
        Reflect.defineMetadata('key', 'data', target)
    }
    return fn
}

@Base('/api')
class Http {
    fileName: string
    constructor(name) {
        this.fileName = name
    }
    @GetData('json')
    getList(@Result() data: any) {
        console.log(data)
    }
}
const http = new Http('orange')

你可能感兴趣的:(typeScript,学习,javascript,前端)