天天看点

ts 装饰器学习总结

装饰器语法

  1. 没参数 @方法名称
  2. 有参数 @方法名称(参数)

    ts装饰器以关键字@开头 必须在class 中

    装饰器就是一个函数 在ts编译成js时执行

1.类装饰器

//定义装饰器 
const testClass = (params?:any)=>(target:any)=>{
	//设置目标类Test value 为装饰器传进来的参数
    target.prototype.value = params
}
// 调用普通装饰器
@testClass('测试') 
class Test {
    value:any
    
}
let test = new Test()
console.log(test.value)
           

类装饰器实用案例

不太容易看懂,建议跟着代码敲一遍。

/**
 * 类装饰器重载构造函数
 * 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数
 * 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
 * @param params 参数
 * @param target HttpClient 原型
 * @returns 用返回的类重写构造函数
 */
 
const logClass = (params:any)=> (target:any)=>{ 
  
    return class  extends target{
        params = params
        apiUrl = '修改后的apiUrl'
        testAttribute = '测试添加属性' 
        getData(){ // 覆盖 getData 方法
            this.apiUrl += '----'
            console.log(this.apiUrl); //修改后的apiUrl----
        }
       
        testMethod(){
            console.log('测试添加方法')
            return '测试添加方法'
        }
    }
} 

 @logClass('参数')
class HttpClient {
    public apiUrl: string | undefined; 
    getData() {
        console.log(this.apiUrl);
    }
    origin(){ //因为装饰器中没有 origin 方法所以 他没有别覆盖掉
     
        return "我没有覆盖"
    }

}
var http: any = new HttpClient();

console.log(http.apiUrl) //修改后的apiUrl
http.getData(); //执行了装饰器里面的方法
console.log(http.testMethod()) //测试添加方法
console.log(http.apiUrl) //修改后的apiUrl----
console.log(http.testAttribute) //测试添加属性
console.log(http.params) //测试添加参数 
console.log(http.origin()) //测试添加参数 
           

2.方法装饰器(用的最多)

/**
 * 
 * @param params 参数
 * @param target class 
 *  @param methodsName  装饰函数名称
 * @param desc 函数描述  里面有个value 为当前函数
 */
const testMethods =(params?:any)=>(target:any,methodsName:any ,desc:any )=>{
 let _methods   =  desc.value; //保存需要封装的函数
    
 desc.value = function(){ // 覆盖封装函数并添加 try catch 
     try {
      return  _methods.apply(this) // 借用封装的函数并返回结果,记得写 return
     } catch (error) {
        console.log(`抱歉${methodsName}出错了`)  
     }
 }

} 


class Test {
    value:any
    //调用 函数装饰器
    @testMethods() //装饰test 函数 记得不能写;
    test(){
        错误 //写一个错误测试一下testMethods效果
    } 
}
let test = new Test() 

test.test()//调用test 方法
           

3.属性装饰器

/**
 * 属性装饰器只能接收到两个参数
 * @param target Test 对应的 prototype
 * @param key  属性名字
 */

const number = (params: any) => (target: any, key: string):PropertyDescriptor | void  => {
    //设置 Test 中的age (装饰属性) = Number(params) 
    target[key] = Number(params) 

    // return {
    //     configurable?: boolean; //是否可以设置
    //     enumerable?: boolean; // 是否可以循环
    //     value?: any; // 强制设置他的值,别人就无法覆盖你的值(不建议使用)
    //     writable?: boolean; // 是否可改
    // }
    
}
 

class Test {
    @number('23') // 设置年龄并转成字符串
    age = 123 // 有值把上面的覆盖

    @number('23') // 设置年龄并转成字符串
    age2 
}

const test = new Test();
console.log(test.age) //  123
console.log(test.age2) //24
           

4.参数装饰器(暂时没找到他有什么用)

/**
 * 参数装饰器定义
 * @param params 传进来的参数
 * @param target  Test的原型  Test.prototype
 * @param methodName // 当前函数名称
 * @param paramIndex 所在函数参数中的下标 
 */
const userName = (params: any) => (target: any, method: string, paramIndex: number) => {
    target.name = params
}

class Test {
    age: any
    setAge(@userName('老吴') age: any) {
        console.log(age)
        this.age = age
    }

} 

const test = new Test();
test.setAge(23)
console.log(test.name) //老吴
console.log(test.age) // 23