需要掌握:
作用
在 不改动源代码 的情况下,增加 额外 功能
应用范围
可以用在 类,属性,类中的方法 或 方法参数 上
注意:不能修饰函数
理解
与 python的装饰器 很相似
其功能与 java的注解 类似,但运行原理不同
应用场景
- 打印日志
- 性能测试
- 权限校验等
- 数据库事务处理
实现原理
本质上是闭包
支持情况
浏览器、Node.js
在当前的 浏览器 或 Node.js 版本中,尚不支持装饰器
因此我们使用使用 Babel 插件 @babel/plugin-proposal-decorators 来将它转换为 浏览器 或 Node.js 中可识别的代码。
typescript
支持装饰器
方法装饰器
普通代码
下面例子中,创建 User 类,里面有 login() 登录方法。
在开发时,经常会测试方法的 执行效率,看是否符合公司要求,在该方法中,两次获取时间,进行相减,计算出登录的 耗时 操作
class User {
login(username:string,password:string):Object{
const start = Date.now()
console.log("用户名:",username)
console.log("密码:",password)
console.log("模拟处理登录操作")
const end = Date.now()
console.log("耗时:",(end-start),"毫秒")
return {
code:0,
message:'登录成功!'
}
}
}
const user = new User()
const res = user.login("lilei","123456")
缺点
由于 测试耗时的代码,与 登录业务的代码不相关,从规范上讲,不应该混到一起
测试耗时的代码,当符合要求后,是要删除的,改动代码后,还要再次进行测试,因为防止 无意中改动关键代码 导致 报错,这样就增加工作量
解决
使用 装饰器,将 测试耗时的代码 放到 装饰器中
定义装饰器
function test_time(target: any, context: any) {
/*
注意:此处第一个参数必须是 this
否则 login() 方法中 this.age 将获取不到 值
*/
return function (this:any , ...args: any[] ){
console.log(`开始执行:${context.name}方法`)
const start = Date.now()
// 通过 call() 方法改变 login() 方法中的this
const res = target.call(this , ...args)
const end = Date.now()
console.log(`结束执行:${context.name}方法,耗时${end-start}毫秒`)
return res
}
}
解释
target:此处表示修饰的方法
context:上下文,有以下属性。
- kind:值固定为字符串method,表示当前为方法装饰器。
- name:所装饰的方法名,类型为字符串或 Symbol 值。
- static:布尔值,表示是否为静态方法。该属性为只读属性。
- private:布尔值,表示是否为私有方法。该属性为只读属性。
- access:对象,包含了方法的存取器,但是只有get()方法用来取值,没有set()方法进行赋值。
- addInitializer():为方法增加初始化函数。
使用装饰器
class User {
age:number = 20
@test_time
login(username:string,password:string):Object{
console.log("age",this.age)
console.log("用户名:",username)
console.log("密码:",password)
return {
code:0,
message:'登录成功!'
}
}
}
执行结果:
始执行:login方法
age 20
用户名: lilei
密码: 123456
结束执行:login方法,耗时1毫秒
结果: { code: 0, message: '登录成功!' }
本质
方法装饰器会改写类的原始方法,实质等同于替代所装饰的函数
class User {
age:number = 20
login(username:string,password:string):Object{
console.log(`开始执行:login方法`)
const start = Date.now()
console.log("age",this.age)
console.log("用户名:",username)
console.log("密码:",password)
const end = Date.now()
console.log(`结束执行:login方法,耗时${end-start}毫秒`)
return {
code:0,
message:'登录成功!'
}
}
}
参考:
https://zhuanlan.zhihu.com/p/189960001
https://typescript.p6p.net/typescript-tutorial/decorator.html