1
- ## 定义 < Badge text = ' WIP ' type = ' warning ' />
1
+ ## 定义
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 ` 求值后必须为一个函数, 它会在运行时被调用, 被装饰的声明信息做为参数传入。
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
4
5
5
了解更多有关装饰器实现原理的知识 👉👉👉 [ Javascript Decorator (装饰器) 实现原理及其使用] ( https://rain120.github.io/study-notes/#/notes/javascript/key-concept/decorator?id=javascript-decorator-装饰器-实现原理及其使用 )
6
6
7
7
### 类型 & 优先级
8
8
9
9
** 优先级依次往下执行**
10
10
11
- 1 . 参数装饰器 ` (Parameter Decorators) `
11
+ 1 . 参数装饰器 ` (Parameter Decorators) `
12
12
13
- ** 参数装饰器** 声明在一个参数声明之前( 紧靠着参数声明) 。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件( .d.ts), 重载或其它外部上下文( 比如 ` declare ` 的类) 里。
13
+ ** 参数装饰器** 声明在一个参数声明之前( 紧靠着参数声明) 。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件` ( .d.ts) ` , 重载或其它外部上下文( 比如 ` declare ` 的类) 里。
14
14
15
15
2 . 方法装饰器 ` (Method Decorators) `
16
16
17
- ** 方法装饰器** 声明在一个方法的声明之前( 紧靠着方法声明) 。 它会被应用到方法的 * 属性描述符* 上, 可以用来监视, 修改或者替换方法定义。 方法装饰器不能用在声明文件( ` .d.ts ` ), 重载或者任何外部上下文( 比如` declare ` 的类) 中。
17
+ ** 方法装饰器** 声明在一个方法的声明之前( 紧靠着方法声明) 。 它会被应用到方法的 * 属性描述符* 上, 可以用来监视, 修改或者替换方法定义。 方法装饰器不能用在声明文件` ( .d.ts) ` , 重载或者任何外部上下文( 比如` declare ` 的类) 中。
18
18
19
19
3 . 访问器或属性装饰器 ` (Accessor or Property Decorators) `
20
20
21
- ** 属性装饰器 ** 声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中( .d.ts), 或者任何外部上下文( 比如 ` declare ` 的类) 里。
21
+ ** 访问器装饰器 ** 声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 * 属性描述符 * 并且可以用来监视, 修改或替换一个访问器的定义。 访问器装饰器不能用在声明文件中 ` ( .d.ts) ` , 或者任何外部上下文( 比如 ` declare ` 的类) 里。
22
22
23
- 1 . 类属性
24
- 2 . 构造函数参数列表 ` (使用类构造函数装饰器时) `
23
+ ** 属性装饰器** 声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中` (.d.ts) ` , 或者任何外部上下文(比如 ` declare ` 的类)里。
25
24
26
- ** Note:** 访问器 ` get ` ` set `
25
+ 1 . 类属性
26
+ 2 . 构造函数参数列表 ` (使用类构造函数装饰器时) `
27
+
28
+ ** Note:** 访问器 ` get ` ` set `
27
29
28
30
4 . 类装饰器 ` (Class Decorators) `
29
31
30
- ** 类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数, 可以** 用来监视, 修改或替换类定义** 。 类装饰器不能用在声明文件中( ` .d.ts ` ), 也不能用在任何外部上下文中(比如` declare ` 的类)。
32
+ ** 类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数, 可以** 用来监视, 修改或替换类定义** 。 类装饰器不能用在声明文件中( ` .d.ts ` ), 也不能用在任何外部上下文中(比如` declare ` 的类)。
31
33
32
34
## 使用
33
35
34
- 若要启用实验性的装饰器特性, 你必须在命令行或` tsconfig.json ` 里启用` experimentalDecorators ` 编译器选项:
36
+ 若要启用实验性的装饰器特性, 你必须在命令行或` tsconfig.json ` 里启用` experimentalDecorators ` 编译器选项:
35
37
36
38
** 命令行** :
37
39
@@ -52,7 +54,7 @@ tsc --target ES5 --experimentalDecorators
52
54
53
55
### 装饰器组合
54
56
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: **
57
+ 多个装饰器可以同时应用声明到一个 [ 类声明] ( 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 ) 上。
56
58
57
59
``` ts
58
60
// 一行写法
@@ -64,32 +66,32 @@ tsc --target ES5 --experimentalDecorators
64
66
isHandsome () {}
65
67
```
66
68
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))$。
69
+ 当复合 ** 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
70
69
71
** Note:** 当在一个地方使用** 多个装饰器** 时
70
72
71
- - ** 由上至下** 依次对装饰器表达式求值
72
- - 执行顺序是 ** 从下往上** 依次执行。
73
+ - ** 由上至下** 依次对装饰器表达式求值
74
+ - 执行顺序是 ** 从下往上** 依次执行。
73
75
74
76
``` ts
75
77
function first() {
76
- console .log (' first: evaluated' );
77
- return (target , propertyKey : string , descriptor : PropertyDescriptor ) => {
78
- console .log (' first: called' )
79
- }
78
+ console .log (' first: evaluated' );
79
+ return (target , propertyKey : string , descriptor : PropertyDescriptor ) => {
80
+ console .log (' first: called' );
81
+ };
80
82
}
81
83
82
84
function second() {
83
- console .log (' second: evaluated' );
84
- return (target , propertyKey : string , descriptor : PropertyDescriptor ) => {
85
- console .log (' second: called' )
86
- }
85
+ console .log (' second: evaluated' );
86
+ return (target , propertyKey : string , descriptor : PropertyDescriptor ) => {
87
+ console .log (' second: called' );
88
+ };
87
89
}
88
90
89
91
class Example {
90
- @second
91
- @first
92
- method() {}
92
+ @second
93
+ @first
94
+ method() {}
93
95
}
94
96
95
97
// 'second: evaluated'
@@ -100,81 +102,199 @@ class Example {
100
102
101
103
### 参数装饰器
102
104
105
+ 参数装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
106
+
107
+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
108
+ 2 . 成员的名字。
109
+ 3 . 参数在函数参数列表中的索引。
110
+
111
+ ::: warning
112
+ 注意: 参数装饰器只能用来监视一个方法的参数是否被传入。
113
+ :::
114
+
115
+ 参数装饰器的返回值会被忽略。
116
+
103
117
``` ts
118
+ function parameterDecorator(value : boolean ) {
119
+ return function (target : any , propertyKey : string , descriptor : PropertyDescriptor ) {
120
+ console .log (' parameterDecorator' );
121
+ };
122
+ }
104
123
105
- ```
124
+ class Boy {
125
+ name: string ;
126
+ age: number ;
127
+ handsome: boolean ;
106
128
129
+ constructor (name , handsome ) {
130
+ this .name = name ;
131
+ this .handsome = handsome ;
132
+ }
107
133
134
+ setAge(@parameterDecorator (' parameterDecorator' ) age : number ) {
135
+ this .age = age ;
136
+ }
137
+ }
138
+ ```
108
139
109
140
### 方法装饰器
110
141
142
+ 方法装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
143
+
144
+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
145
+ 2 . 成员的名字。
146
+ 3 . 成员的 ** 属性描述符** 。
147
+
148
+ ::: warning
149
+ 如果代码输出目标版本小于` ES5 ` , * 属性描述符* 将会是` undefined ` 。
150
+ :::
151
+
152
+ 如果方法装饰器返回一个值, 它会被用作方法的* 属性描述符* 。
153
+
154
+ ::: warning
155
+ 如果代码输出目标版本小于` ES5 ` 返回值会被忽略。
156
+ :::
157
+
111
158
``` ts
159
+ function methodDecorator(value : boolean ) {
160
+ return function (target : any , propertyKey : string , descriptor : PropertyDescriptor ) {
161
+ target [propertyKey ] = value ;
162
+ };
163
+ }
112
164
113
- ```
165
+ class Boy {
166
+ name: string ;
167
+ handsome: boolean ;
114
168
169
+ @propertyDecorator (' 属性装饰器' , Boy )
170
+ public age: number = 18 ;
115
171
172
+ constructor (name , handsome ) {
173
+ this .name = name ;
174
+ this .handsome = handsome ;
175
+ }
176
+
177
+ @methodDecorator (true )
178
+ isHandsome() {
179
+ return this .handsome ;
180
+ }
181
+ }
182
+ ```
116
183
117
184
### 访问器或属性装饰器
118
185
119
186
#### 属性装饰器
120
187
188
+ 属性装饰器表达式会在运行时当作函数被调用, 传入下列 ` 2 ` 个参数:
189
+
190
+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
191
+ 2 . 成员的名字。
192
+
193
+ ::: warning
194
+ ** 属性描述符** 不会做为参数传入属性装饰器, 这与` TypeScript ` 是如何初始化属性装饰器的有关。 因为目前没有办法在定义一个原型对象的成员时描述一个实例属性, 并且没办法监视或修改一个属性的初始化方法。返回值也会被忽略。因此, 属性描述符只能用来监视类中是否声明了某个名字的属性。
195
+ :::
196
+
121
197
``` ts
122
198
function propertyDecorator(value : string , theClass ) {
123
- console .log (value )
124
- return function (prototype , key ){
125
- console .log (' AccessDecorator' )
126
- }
199
+ console .log (value );
200
+ return function (prototype , key ) {
201
+ console .log (' AccessDecorator' );
202
+ };
127
203
}
128
204
129
205
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
- }
206
+ name: string ;
207
+ handsome: boolean ;
208
+
209
+ @propertyDecorator (' 属性装饰器' , Boy )
210
+ public age: number = 18 ;
211
+
212
+ constructor (name , handsome ) {
213
+ this .name = name ;
214
+ this .handsome = handsome ;
215
+ }
216
+
217
+ @AccessDecorator (' 访问器装饰器' )
218
+ get isHandsome() {
219
+ return this .handsome ;
220
+ }
145
221
}
146
222
```
147
223
224
+ #### 访问器装饰器
225
+
226
+ ::: warning
227
+ ` TypeScript ` 不允许同时装饰一个成员的` get ` 和 ` set ` 访问器。取而代之的是, 一个成员的所有装饰的必须应用在文档顺序的第一个访问器上。这是因为, 在装饰器应用于一个** 属性描述符** 时, 它联合了 ` get ` 和 ` set ` 访问器, 而不是分开声明的。
228
+ :::
148
229
230
+ 访问器装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
149
231
150
- #### 访问器装饰器
232
+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
233
+ 2 . 成员的名字。
234
+ 3 . 成员的** 属性描述符** 。
235
+
236
+ ::: warning
237
+ 如果代码输出目标版本小于 ` ES5 ` , ** Property Descriptor** 将会是 ` undefined ` 。
238
+ :::
239
+
240
+ 如果访问器装饰器返回一个值, 它会被用作方法的* 属性描述符* 。
241
+
242
+ ::: warning
243
+ 如果代码输出目标版本小于 ` ES5 ` 返回值会被忽略。
244
+ :::
151
245
152
246
``` ts
153
247
function AccessDecorator(value : string ) {
154
- console .log (value )
155
- return function (){
156
- console .log (' AccessDecorator' )
157
- }
248
+ console .log (value );
249
+ return function () {
250
+ console .log (' AccessDecorator' );
251
+ };
158
252
}
159
253
160
254
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
- }
255
+ name: string ;
256
+ handsome: boolean ;
257
+
258
+ constructor (name , handsome ) {
259
+ this .name = name ;
260
+ this .handsome = handsome ;
261
+ }
262
+
263
+ @AccessDecorator (' 访问器装饰器' )
264
+ get isHandsome() {
265
+ return this .handsome ;
266
+ }
173
267
}
174
268
```
175
269
176
270
### 类装饰器
177
271
272
+ 类装饰器表达式会在运行时当作函数被调用, ** 类的构造函数作为其唯一的参数** 。
273
+
274
+ 如果类装饰器返回一个值, 它会使用提供的构造函数来替换类的声明。
275
+
276
+ ::: warning
277
+ 如果你要返回一个新的构造函数, 你必须注意处理好原来的原型链。在运行时的装饰器调用逻辑中 ** 不会** 为你做这些。
278
+ :::
279
+
280
+ ``` ts
281
+ function sealed(constructor : Function ) {
282
+ Object .seal (constructor );
283
+ Object .seal (constructor .prototype );
284
+ }
285
+
286
+ @sealed
287
+ class Greeter {
288
+ greeting: string ;
289
+ constructor (message : string ) {
290
+ this .greeting = message ;
291
+ }
292
+ greet() {
293
+ return ' Hello, ' + this .greeting ;
294
+ }
295
+ }
296
+ ```
297
+
178
298
## 快来耍耍啊
179
299
180
300
### 🌰🌰
@@ -203,4 +323,4 @@ class Boy {
203
323
204
324
[ handbook - decorators] ( https://www.typescriptlang.org/docs/handbook/decorators.html )
205
325
206
- [ 使用 TypeScript 装饰器装饰你的代码] ( https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4 )
326
+ [ 使用 TypeScript 装饰器装饰你的代码] ( https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4 )
0 commit comments