1- ## 定义 < Badge text = ' WIP ' type = ' warning ' />
1+ ## 定义
22
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 ` 求值后必须为一个函数, 它会在运行时被调用, 被装饰的声明信息做为参数传入。
44
55了解更多有关装饰器实现原理的知识 👉👉👉 [ Javascript Decorator (装饰器) 实现原理及其使用] ( https://rain120.github.io/study-notes/#/notes/javascript/key-concept/decorator?id=javascript-decorator-装饰器-实现原理及其使用 )
66
77### 类型 & 优先级
88
99** 优先级依次往下执行**
1010
11- 1 . 参数装饰器 ` (Parameter Decorators) `
11+ 1 . 参数装饰器 ` (Parameter Decorators) `
1212
13- ** 参数装饰器** 声明在一个参数声明之前( 紧靠着参数声明) 。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件( .d.ts), 重载或其它外部上下文( 比如 ` declare ` 的类) 里。
13+ ** 参数装饰器** 声明在一个参数声明之前( 紧靠着参数声明) 。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件` ( .d.ts) ` , 重载或其它外部上下文( 比如 ` declare ` 的类) 里。
1414
15152 . 方法装饰器 ` (Method Decorators) `
1616
17- ** 方法装饰器** 声明在一个方法的声明之前( 紧靠着方法声明) 。 它会被应用到方法的 * 属性描述符* 上, 可以用来监视, 修改或者替换方法定义。 方法装饰器不能用在声明文件( ` .d.ts ` ), 重载或者任何外部上下文( 比如` declare ` 的类) 中。
17+ ** 方法装饰器** 声明在一个方法的声明之前( 紧靠着方法声明) 。 它会被应用到方法的 * 属性描述符* 上, 可以用来监视, 修改或者替换方法定义。 方法装饰器不能用在声明文件` ( .d.ts) ` , 重载或者任何外部上下文( 比如` declare ` 的类) 中。
1818
19193 . 访问器或属性装饰器 ` (Accessor or Property Decorators) `
2020
21- ** 属性装饰器 ** 声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中( .d.ts), 或者任何外部上下文( 比如 ` declare ` 的类) 里。
21+ ** 访问器装饰器 ** 声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 * 属性描述符 * 并且可以用来监视, 修改或替换一个访问器的定义。 访问器装饰器不能用在声明文件中 ` ( .d.ts) ` , 或者任何外部上下文( 比如 ` declare ` 的类) 里。
2222
23- 1 . 类属性
24- 2 . 构造函数参数列表 ` (使用类构造函数装饰器时) `
23+ ** 属性装饰器** 声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中` (.d.ts) ` , 或者任何外部上下文(比如 ` declare ` 的类)里。
2524
26- ** Note:** 访问器 ` get ` ` set `
25+ 1 . 类属性
26+ 2 . 构造函数参数列表 ` (使用类构造函数装饰器时) `
27+
28+ ** Note:** 访问器 ` get ` ` set `
2729
28304 . 类装饰器 ` (Class Decorators) `
2931
30- ** 类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数, 可以** 用来监视, 修改或替换类定义** 。 类装饰器不能用在声明文件中( ` .d.ts ` ), 也不能用在任何外部上下文中(比如` declare ` 的类)。
32+ ** 类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数, 可以** 用来监视, 修改或替换类定义** 。 类装饰器不能用在声明文件中( ` .d.ts ` ), 也不能用在任何外部上下文中(比如` declare ` 的类)。
3133
3234## 使用
3335
34- 若要启用实验性的装饰器特性, 你必须在命令行或` tsconfig.json ` 里启用` experimentalDecorators ` 编译器选项:
36+ 若要启用实验性的装饰器特性, 你必须在命令行或` tsconfig.json ` 里启用` experimentalDecorators ` 编译器选项:
3537
3638** 命令行** :
3739
@@ -52,7 +54,7 @@ tsc --target ES5 --experimentalDecorators
5254
5355### 装饰器组合
5456
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 ) 上。
5658
5759``` ts
5860// 一行写法
@@ -64,32 +66,32 @@ tsc --target ES5 --experimentalDecorators
6466isHandsome () {}
6567```
6668
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))$。
6870
6971** Note:** 当在一个地方使用** 多个装饰器** 时
7072
71- - ** 由上至下** 依次对装饰器表达式求值
72- - 执行顺序是 ** 从下往上** 依次执行。
73+ - ** 由上至下** 依次对装饰器表达式求值
74+ - 执行顺序是 ** 从下往上** 依次执行。
7375
7476``` ts
7577function 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+ };
8082}
8183
8284function 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+ };
8789}
8890
8991class Example {
90- @second
91- @first
92- method() {}
92+ @second
93+ @first
94+ method() {}
9395}
9496
9597// 'second: evaluated'
@@ -100,81 +102,199 @@ class Example {
100102
101103### 参数装饰器
102104
105+ 参数装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
106+
107+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
108+ 2 . 成员的名字。
109+ 3 . 参数在函数参数列表中的索引。
110+
111+ ::: warning
112+ 注意: 参数装饰器只能用来监视一个方法的参数是否被传入。
113+ :::
114+
115+ 参数装饰器的返回值会被忽略。
116+
103117``` ts
118+ function parameterDecorator(value : boolean ) {
119+ return function (target : any , propertyKey : string , descriptor : PropertyDescriptor ) {
120+ console .log (' parameterDecorator' );
121+ };
122+ }
104123
105- ```
124+ class Boy {
125+ name: string ;
126+ age: number ;
127+ handsome: boolean ;
106128
129+ constructor (name , handsome ) {
130+ this .name = name ;
131+ this .handsome = handsome ;
132+ }
107133
134+ setAge(@parameterDecorator (' parameterDecorator' ) age : number ) {
135+ this .age = age ;
136+ }
137+ }
138+ ```
108139
109140### 方法装饰器
110141
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+
111158``` ts
159+ function methodDecorator(value : boolean ) {
160+ return function (target : any , propertyKey : string , descriptor : PropertyDescriptor ) {
161+ target [propertyKey ] = value ;
162+ };
163+ }
112164
113- ```
165+ class Boy {
166+ name: string ;
167+ handsome: boolean ;
114168
169+ @propertyDecorator (' 属性装饰器' , Boy )
170+ public age: number = 18 ;
115171
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+ ```
116183
117184### 访问器或属性装饰器
118185
119186#### 属性装饰器
120187
188+ 属性装饰器表达式会在运行时当作函数被调用, 传入下列 ` 2 ` 个参数:
189+
190+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
191+ 2 . 成员的名字。
192+
193+ ::: warning
194+ ** 属性描述符** 不会做为参数传入属性装饰器, 这与` TypeScript ` 是如何初始化属性装饰器的有关。 因为目前没有办法在定义一个原型对象的成员时描述一个实例属性, 并且没办法监视或修改一个属性的初始化方法。返回值也会被忽略。因此, 属性描述符只能用来监视类中是否声明了某个名字的属性。
195+ :::
196+
121197``` ts
122198function 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+ };
127203}
128204
129205class 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+ }
145221}
146222```
147223
224+ #### 访问器装饰器
225+
226+ ::: warning
227+ ` TypeScript ` 不允许同时装饰一个成员的` get ` 和 ` set ` 访问器。取而代之的是, 一个成员的所有装饰的必须应用在文档顺序的第一个访问器上。这是因为, 在装饰器应用于一个** 属性描述符** 时, 它联合了 ` get ` 和 ` set ` 访问器, 而不是分开声明的。
228+ :::
148229
230+ 访问器装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
149231
150- #### 访问器装饰器
232+ 1 . 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
233+ 2 . 成员的名字。
234+ 3 . 成员的** 属性描述符** 。
235+
236+ ::: warning
237+ 如果代码输出目标版本小于 ` ES5 ` , ** Property Descriptor** 将会是 ` undefined ` 。
238+ :::
239+
240+ 如果访问器装饰器返回一个值, 它会被用作方法的* 属性描述符* 。
241+
242+ ::: warning
243+ 如果代码输出目标版本小于 ` ES5 ` 返回值会被忽略。
244+ :::
151245
152246``` ts
153247function 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+ };
158252}
159253
160254class 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+ }
173267}
174268```
175269
176270### 类装饰器
177271
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+
178298## 快来耍耍啊
179299
180300### 🌰🌰
@@ -203,4 +323,4 @@ class Boy {
203323
204324[ handbook - decorators] ( https://www.typescriptlang.org/docs/handbook/decorators.html )
205325
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