装饰器语法

62 阅读5分钟

什么是装饰器?

装饰器是一种编程概念,用于在不修改原始代码的情况下,为代码元素(如函数、方法、‌等)添加额外的功能或行为。 装饰器以@符号为前缀,后跟一个函数或类,它附着在类、方法、属性等代码元素上,并在运行时对这些元素进行注释或修改。装饰器的使用主要在两种情况下:

  1. 在‌TypeScript,装饰器是一种特殊类型的声明,用于增强代码功能的声明。它们提供了一种在类、方法、属性等代码元素上注释或修改的方式,使得我们可以通过装饰器来扩展、修改或监视代码的行为。‌
  2. 在‌Python,装饰器是一个函数或类,用于增强其他函数或方法的功能而不改变其结构。装饰器的本质是一个闭包函数,它接受一个函数作为参数,返回一个新的函数,并在返回的函数中执行原函数以及额外的功能。‌

装饰器的应用场景广泛,包括但不限于性能测试、打印日志、用户验证、日志记录、性能分析、缓存、权限验证等。通过使用装饰器,可以提高代码的可维护性、灵活性和复用性。

装饰器的种类

//1.类装饰器 ClassDecorator target 构造函数
//2.属性装饰器 PropertyDecorator
//3.参数装饰器 ParameterDecorator
//4.方法装饰器 MethodDecorator PropertyDescriptor  
//5.装饰器工厂
//6.import 'reflect-metadata
//7.axios

类装饰器

最初实现
const Base:ClassDecorator = (target) => { 
  console.log(
    target
  )
}
@Base
class Http {

}

这是一个简单的函数,我们执行 ts-node index.ts 那么就可以读取到结果

有了构造函数可以干什么?(不去破坏原有的结构)

我不想读原有的几千行代码,我又要增加属性、方法,怎么做?

const Base:ClassDecorator = (target) => {
  console.log(target)
  target.prototype.name = '胡子铭'
  target.prototype.funny = () =>{
    console.log('我是XXXX')
  }
}
@Base
class Http {
    // 。。。。。
}
const http =new Http() as any
http.funny()
console.log(http.name)
Base(Http)

我想要自定义怎么做?使用函数柯里化

函数柯里化==装饰器工厂(定义一个函数,相当于闭包)
const Base = (name:string) => {
  const fn:ClassDecorator = (target) =>{
    console.log(target)
    target.prototype.name = name
    target.prototype.funny = () =>{
      console.log('11514')
    }
  }
  return fn
}
@Base('qian duan')
class Http {
    // 。。。。。
}
const http =new Http() as any
http.funny()
console.log(http.name)

20bcbf58c0eba95e7d6f8b47c98beb1e.png

方法装饰器

类里面实现get和post请求

在类的中心呼唤mock(地址:api.apiopen.top/api/getHaoK…

MethodDecorator可以读出三个属性,target、key、descriptor(这里读取的是原型对象了,不是这个构造函数)

const Base = (name:string) => {
  const fn:ClassDecorator = (target) =>// console.log(target)
    target.prototype.name = name
    target.prototype.funny = () =>{
      // console.log('11514')
    }
  }
  return fn
}
const Get = (url:string) =>{
    const  fn:MethodDecorator = (target,key,descriptor) =>{
        console.log(target,key,descriptor)
    }
    return fn
}
@Base('qian duan')

class Http {
    @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    getList(data:any){
      console.log(data)
    }
}
const http =new Http() as any 
http.funny()
// console.log(http.name)

可以看到我们这三个对象返回的参数

使用axios调用接口

node只能用http,用axios更方便一点

cnpm i axios
import axios from "axios"
const Base = (name:string) => {
  const fn:ClassDecorator = (target) =>{
    // console.log(target)
    target.prototype.name = name
    target.prototype.funny = () =>{
      // console.log('11514')
    }
  }
  return fn
}
const Get = (url:string) =>{
    const  fn:MethodDecorator = (target,key,descriptor:PropertyDescriptor) =>{
        // console.log(target,key,descriptor)
        axios.get(url).then(res =>{
          descriptor.value(res.data)
        })
    }
    return fn
}
@Base('qian duan')

class Http {
    @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    getList(data:any){
      console.log(data)
    }
}
const http =new Http() as any
http.funny()
// console.log(http.name) 

可以照着这个方法实现一个POST请求

//1.类装饰器 ClassDecorator target 构造函数
//2.属性装饰器 PropertyDecorator
//3.参数装饰器 ParameterDecorator
//4.方法装饰器 MethodDecorator PropertyDescriptor
//5.装饰器工厂
//6.import 'reflect-metadata
//7.axios
import axios from "axios"
const Base = (name:string) => {
  const fn:ClassDecorator = (target) =>{
    // console.log(target)
    target.prototype.name = name
    target.prototype.funny = () =>{
      // console.log('11514')
    }
  }
  return fn
}
const Get = (url:string) =>{
    const  fn:MethodDecorator = (target,key,descriptor:PropertyDescriptor) =>{
        // console.log(target,key,descriptor)
        axios.get(url).then(res =>{
          descriptor.value(res.data)
        })
    }
    return fn
}
const POST = (url:string) =>{
  const  fn:MethodDecorator = (target,key,descriptor:PropertyDescriptor) =>{
      // console.log(target,key,descriptor)
      axios.post(url).then(res =>{
        descriptor.value(res.data)
      })
  }
  return fn
}

@Base('qian duan')

class Http {
    // @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    @POST('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    getList(data:any){
      console.log(data)
    }
}
const http =new Http() as any
http.funny()
// console.log(http.name)

参数装饰器和reflector

import 'reflect-metadata'
import axios from "axios"
const Base = (name:string) => {
  const fn:ClassDecorator = (target) =>{
    // console.log(target)
    target.prototype.name = name
    target.prototype.funny = () =>{
      // console.log('11514')
    }
  }
  return fn
}
const Get = (url:string) =>{
    const  fn:MethodDecorator = (target,_:any,descriptor:PropertyDescriptor) =>{
      // 取值
      const key = Reflect.getMetadata('key',target)
        // console.log(target,key,descriptor)
        axios.get(url).then(res =>{
          descriptor.value(key?res.data[key]:res.data)
        })
    }
    return fn
}
// const POST = (url:string) =>{
//   const  fn:MethodDecorator = (target,key,descriptor:PropertyDescriptor) =>{
//       // console.log(target,key,descriptor)
//       axios.post(url).then(res =>{
//         descriptor.value(res.data)
//       })
//   }
//   return fn
// }
const Result = () =>{
  const fn:ParameterDecorator = (target,propertyKey,parameterIndex) =>{
      // console.log(target,propertyKey,parameterIndex)
      // 存值
      Reflect.defineMetadata('key','result',target)
  }
  return fn
}

@Base('qian duan')

class Http {
    // @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    getList(@Result() data:any){
      console.log(data)
    }
}
const http =new Http() as any
http.funny()
// console.log(http.name)

属性装饰器

import 'reflect-metadata'
import axios from "axios"
const Base = (name:string) => {
  const fn:ClassDecorator = (target) =>{
    // console.log(target)
    target.prototype.name = name
    target.prototype.funny = () =>{
      // console.log('11514')
    }
  }
  return fn
}
const Get = (url:string) =>{
    const  fn:MethodDecorator = (target,_:any,descriptor:PropertyDescriptor) =>{
      // 取值
      const key = Reflect.getMetadata('key',target)
        // console.log(target,key,descriptor)
        axios.get(url).then(res =>{
          descriptor.value(key?res.data[key]:res.data)
        })
    }
    return fn
}
// const POST = (url:string) =>{
//   const  fn:MethodDecorator = (target,key,descriptor:PropertyDescriptor) =>{
//       // console.log(target,key,descriptor)
//       axios.post(url).then(res =>{
//         descriptor.value(res.data)
//       })
//   }
//   return fn
// }
const Result = () =>{
  const fn:ParameterDecorator = (target,propertyKey,parameterIndex) =>{
      // console.log(target,propertyKey,parameterIndex)
      // 存值
      Reflect.defineMetadata('key','result',target)
  }
  return fn
}


const Name:PropertyDecorator =(target,key)=>{
console.log(target,key)
}
@Base('qian duan')
class Http {
    // @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    @Name
    huziming:string
    constructor(){
      this.huziming = '?'
    }
    @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
    getList(@Result() data:any){
      // console.log(data)
    }
}
const http =new Http() as any
http.funny()
// console.log(http.name)