一、是什么

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上

是一种在不改变原类和使用继承的情况下,动态地扩展对象功能

同样的,本质也不是什么高大上的结构,就是一个普通的函数,@expression 的形式其实是Object.defineProperty的语法糖

expression求值后必须也是一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入

二、使用方式

由于typescript是一个实验性特性,若要使用,需要在tsconfig.json文件启动,如下:

{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
 

typescript装饰器的使用和javascript基本一致

类的装饰器可以装饰:

  • 方法/属性

  • 参数

  • 访问器

类装饰

例如声明一个函数 addAge 去给 Class 的属性 age 添加年龄.

function addAge(constructor: Function) {
constructor.prototype.age = 18;
} @addAge
class Person{
name: string;
age!: number;
constructor() {
this.name = 'huihui';
}
} let person = new Person(); console.log(person.age); // 18
 

上述代码,实际等同于以下形式:

Person = addAge(function Person() { ... });

上述可以看到,当装饰器作为修饰类的时候,会把构造器传递进去。constructor.prototype.age 就是在每一个实例化对象上面添加一个 age 属性

方法/属性装饰

同样,装饰器可以用于修饰类的方法,这时候装饰器函数接收的参数变成了:

  • target:对象的原型
  • propertyKey:方法的名称
  • descriptor:方法的属性描述符

可以看到,这三个属性实际就是Object.defineProperty的三个参数,如果是类的属性,则没有传递第三个参数

如下例子:

// 声明装饰器修饰方法/属性
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(target);
console.log("prop " + propertyKey);
console.log("desc " + JSON.stringify(descriptor) + "\n\n");
descriptor.writable = false;
}; function property(target: any, propertyKey: string) {
console.log("target", target)
console.log("propertyKey", propertyKey)
} class Person{
@property
name: string;
constructor() {
this.name = 'huihui';
} @method
say(){
return 'instance method';
} @method
static run(){
return 'static method';
}
} const xmz = new Person(); // 修改实例方法say
xmz.say = function() {
return 'edit'
}
 

输出如下图所示:

参数装饰

接收3个参数,分别是:

  • target :当前对象的原型
  • propertyKey :参数的名称
  • index:参数数组中的位置
function logParameter(target: Object, propertyName: string, index: number) {
console.log(target);
console.log(propertyName);
console.log(index);
} class Employee {
greet(@logParameter message: string): string {
return `hello ${message}`;
}
}
const emp = new Employee();
emp.greet('hello');
 

输入如下图:

访问器装饰

使用起来方式与方法装饰一致,如下:

 
function modification(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(target);
console.log("prop " + propertyKey);
console.log("desc " + JSON.stringify(descriptor) + "\n\n");
}; class Person{
_name: string;
constructor() {
this._name = 'huihui';
} @modification
get name() {
return this._name
}
}
 

装饰器工厂

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

function addAge(age: number) {
return function(constructor: Function) {
constructor.prototype.age = age
}
} @addAge(10)
class Person{
name: string;
age!: number;
constructor() {
this.name = 'huihui';
}
} let person = new Person();
 

执行顺序

当多个装饰器应用于一个声明上,将由上至下依次对装饰器表达式求值,求值的结果会被当作函数,由下至上依次调用,例如如下:

function f() {
console.log("f(): evaluated");
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("f(): called");
}
} function g() {
console.log("g(): evaluated");
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("g(): called");
}
} class C {
@f()
@g()
method() {}
} // 输出
f(): evaluated
g(): evaluated
g(): called
f(): called
 

三、应用场景

可以看到,使用装饰器存在两个显著的优点:

  • 代码可读性变强了,装饰器命名相当于一个注释
  • 在不改变原有代码情况下,对原来功能进行扩展

后面的使用场景中,借助装饰器的特性,除了提高可读性之后,针对已经存在的类,可以通过装饰器的特性,在不改变原有代码情况下,对原来功能进行扩展

最新文章

  1. Python 爬虫模拟登陆知乎
  2. Leetcode Word Ladder
  3. [原创]cocos2d-x研习录-第二阶 概念类之节点类(CCNode)
  4. (转)windows下安装nodejs及框架express
  5. shell中的内建命令, 函数和外部命令
  6. utube视频落地
  7. Linux进程管理—信号、定时器
  8. Spring知识点回顾(02)AOP
  9. 拆系数FFT及其部分优化
  10. iSlide——图标库、图示库的用法
  11. Socket实例
  12. 未安装Oracle客户端的服务器上,使用ASP.NET远程连接Oracle
  13. hihocoder#1333 : 平衡树·Splay2 (区间操作)
  14. 【题解】Luogu P4054 [JSOI2009]计数问题
  15. vue 中使用iconfont Unicode编码线上字体图标的流程
  16. 如何对vue项目进行优化,加快首页加载速度
  17. 设置eclipse/myeclipse的智能提示
  18. IIS 6.0/7.0/7.5、Nginx、Apache 等服务器解析漏洞总结
  19. GreenPlum:基于PostgreSQL的分布式关系型数据库
  20. Jquery~跨域异步上传文件

热门文章

  1. 年薪60W的Android程序员究竟多累、多苦?一条高赞评论扎了无数人的心
  2. Golang语言系列-10-包
  3. HTTP头参数详解及其中的危险
  4. Linux提权手法整理
  5. NOIP 模拟 $17\; \rm weight$
  6. snoop的基本用法
  7. C++类的构造函数后面加一个冒号的含义
  8. 【java虚拟机】jvm调优原则
  9. Spring中Resource(资源)的获取
  10. 安装Ubuntu服务器版 + 远程连接ssh +更换阿里云源