|
1 | 1 | ## 定义 <Badge text='WIP' type='warning' /> |
2 | 2 |
|
| 3 | +**装饰器**是一种特殊类型的声明,它能够被附加到[类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators),[方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators), [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators),[属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)或[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。 装饰器使用 `@expression`这种形式,`expression`求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。 |
| 4 | + |
| 5 | +了解更多有关装饰器实现原理的知识 👉👉👉 [Javascript Decorator (装饰器) 实现原理及其使用](https://rain120.github.io/study-notes/#/notes/javascript/key-concept/decorator?id=javascript-decorator-装饰器-实现原理及其使用) |
| 6 | + |
| 7 | +### 类型 & 优先级 |
| 8 | + |
| 9 | +**优先级依次往下执行** |
| 10 | + |
| 11 | +1. 参数装饰器 `(Parameter Decorators)` |
| 12 | + |
| 13 | + **参数装饰器**声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件(.d.ts),重载或其它外部上下文(比如 `declare`的类)里。 |
| 14 | + |
| 15 | +2. 方法装饰器 `(Method Decorators)` |
| 16 | + |
| 17 | + **方法装饰器**声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的 *属性描述符*上,可以用来监视,修改或者替换方法定义。 方法装饰器不能用在声明文件( `.d.ts`),重载或者任何外部上下文(比如`declare`的类)中。 |
| 18 | + |
| 19 | +3. 访问器或属性装饰器 `(Accessor or Property Decorators)` |
| 20 | + |
| 21 | + **属性装饰器**声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如 `declare`的类)里。 |
| 22 | + |
| 23 | + 1. 类属性 |
| 24 | + 2. 构造函数参数列表 `(使用类构造函数装饰器时)` |
| 25 | + |
| 26 | + **Note:** 访问器 `get` `set` |
| 27 | + |
| 28 | +4. 类装饰器 `(Class Decorators)` |
| 29 | + |
| 30 | + **类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数,可以**用来监视,修改或替换类定义**。 类装饰器不能用在声明文件中( `.d.ts`),也不能用在任何外部上下文中(比如`declare`的类)。 |
| 31 | + |
3 | 32 | ## 使用 |
4 | 33 |
|
| 34 | +若要启用实验性的装饰器特性,你必须在命令行或`tsconfig.json`里启用`experimentalDecorators`编译器选项: |
| 35 | + |
| 36 | +**命令行**: |
| 37 | + |
| 38 | +```shell |
| 39 | +tsc --target ES5 --experimentalDecorators |
| 40 | +``` |
| 41 | + |
| 42 | +**tsconfig.json**: |
| 43 | + |
| 44 | +```json |
| 45 | +{ |
| 46 | + "compilerOptions": { |
| 47 | + "target": "ES5", |
| 48 | + "experimentalDecorators": true |
| 49 | + } |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +### 装饰器组合 |
| 54 | + |
| 55 | +多个装饰器可以同时应用声明到一个 [类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators),[方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators), [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators),[属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)或[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。**Eg:** |
| 56 | + |
| 57 | +```ts |
| 58 | +// 一行写法 |
| 59 | +@f @g isHandsome() {} |
| 60 | + |
| 61 | +// 多行写法 ----> 个人喜欢这种写法 |
| 62 | +@f |
| 63 | +@g |
| 64 | +isHandsome() {} |
| 65 | +``` |
| 66 | + |
| 67 | +当复合 **f** 和 **g** 时,[复合](https://zh.wikipedia.org/wiki/%E5%A4%8D%E5%90%88%E5%87%BD%E6%95%B0) `(把一个函数的输出作为另一个函数的输入)`的结果 $(f ∘ g)(x) = f(g(x))$。 |
| 68 | + |
| 69 | +**Note:** 当在一个地方使用**多个装饰器**时 |
| 70 | + |
| 71 | +- **由上至下**依次对装饰器表达式求值 |
| 72 | +- 执行顺序是 **从下往上** 依次执行。 |
| 73 | + |
| 74 | +```ts |
| 75 | +function first() { |
| 76 | + console.log('first: evaluated'); |
| 77 | + return (target, propertyKey: string, descriptor: PropertyDescriptor) => { |
| 78 | + console.log('first: called') |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +function second() { |
| 83 | + console.log('second: evaluated'); |
| 84 | + return (target, propertyKey: string, descriptor: PropertyDescriptor) => { |
| 85 | + console.log('second: called') |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +class Example { |
| 90 | + @second |
| 91 | + @first |
| 92 | + method() {} |
| 93 | +} |
| 94 | + |
| 95 | +// 'second: evaluated' |
| 96 | +// 'first: evaluated' |
| 97 | +// 'first: called' |
| 98 | +// 'second: called' |
| 99 | +``` |
| 100 | + |
| 101 | +### 参数装饰器 |
| 102 | + |
| 103 | +```ts |
| 104 | + |
| 105 | +``` |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | +### 方法装饰器 |
| 110 | + |
| 111 | +```ts |
| 112 | + |
| 113 | +``` |
| 114 | + |
| 115 | + |
| 116 | + |
| 117 | +### 访问器或属性装饰器 |
| 118 | + |
| 119 | +#### 属性装饰器 |
| 120 | + |
| 121 | +```ts |
| 122 | +function propertyDecorator(value: string, theClass) { |
| 123 | + console.log(value) |
| 124 | + return function(prototype, key){ |
| 125 | + console.log('AccessDecorator') |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +class Boy { |
| 130 | + name: string; |
| 131 | + handsome: boolean; |
| 132 | + |
| 133 | + @propertyDecorator('属性装饰器', Boy) |
| 134 | + public age: number = 18; |
| 135 | + |
| 136 | + constructor(name, handsome) { |
| 137 | + this.name = name; |
| 138 | + this.handsome = handsome; |
| 139 | + } |
| 140 | + |
| 141 | + @AccessDecorator('访问器装饰器') |
| 142 | + get isHandsome() { |
| 143 | + return this.handsome; |
| 144 | + } |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | + |
| 149 | + |
| 150 | +#### 访问器装饰器 |
| 151 | + |
| 152 | +```ts |
| 153 | +function AccessDecorator(value: string) { |
| 154 | + console.log(value) |
| 155 | + return function(){ |
| 156 | + console.log('AccessDecorator') |
| 157 | + } |
| 158 | +} |
| 159 | + |
| 160 | +class Boy { |
| 161 | + name: string; |
| 162 | + handsome: boolean; |
| 163 | + |
| 164 | + constructor(name, handsome) { |
| 165 | + this.name = name; |
| 166 | + this.handsome = handsome; |
| 167 | + } |
| 168 | + |
| 169 | + @AccessDecorator('访问器装饰器') |
| 170 | + get isHandsome() { |
| 171 | + return this.handsome; |
| 172 | + } |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +### 类装饰器 |
| 177 | + |
5 | 178 | ## 快来耍耍啊 |
6 | 179 |
|
7 | 180 | ### 🌰🌰 |
|
29 | 202 | ## 参考资料 |
30 | 203 |
|
31 | 204 | [handbook - decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) |
| 205 | + |
| 206 | +[使用 TypeScript 装饰器装饰你的代码](https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4) |
0 commit comments