Skip to content

Commit de57ffb

Browse files
committed
feat: update articles
1 parent 46a5827 commit de57ffb

1 file changed

Lines changed: 89 additions & 1 deletion

File tree

‎JavaScript/TypeScript/类型使用/Decorator.md‎

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ function foo(target) {
106106
}
107107
};
108108
}
109+
109110
@foo
110111
class P {
111112
constructor() {}
@@ -160,6 +161,8 @@ p.test('Hello Jony');
160161

161162
所谓注解的定义就是:为相应的类附加元数据支持。所谓元数据可以简单的解释,就是修饰数据的数据,比如一个人有 name,age 等数据属性,那么 name 和 age 这些字段就是为了修饰数据的数据,可以简单的称为元数据。通过注解添加元数据,然后在装饰器中获取这些元数据,完成对类、类的方法等等的修改,可以在装饰器中添加元数据的支持,比如可以可以在装饰器工厂函数以及装饰器函数中添加元数据支持等。
162163

164+
## 注解使用
165+
163166
Reflect Metadata 是 ES7 的一个提案,它主要用来在声明的时候添加和读取元数据。Reflect Metadata 的 API 可以用于类或者类的属性上,如:
164167

165168
```ts
@@ -172,10 +175,67 @@ function metadata(
172175
};
173176
```
174177

175-
## 注解使用
178+
Reflect.metadata 当作 Decorator 使用,当修饰类时,在类上添加元数据,当修饰类属性时,在类原型的属性上添加元数据,如:
179+
180+
```ts
181+
@Reflect.metadata('inClass', 'A')
182+
class Test {
183+
@Reflect.metadata('inMethod', 'B')
184+
public hello(): string {
185+
return 'hello world';
186+
}
187+
}
188+
189+
console.log(Reflect.getMetadata('inClass', Test)); // 'A'
190+
console.log(Reflect.getMetadata('inMethod', new Test(), 'hello')); // 'B'
191+
```
192+
193+
譬如在 vue-property-decorator 6.1 及其以下版本中,通过使用 Reflect.getMetadata API,Prop Decorator 能获取属性类型传至 Vue,简要代码如下:
194+
195+
```ts
196+
function Prop(): PropertyDecorator {
197+
return (target, key: string) => {
198+
const type = Reflect.getMetadata('design:type', target, key);
199+
console.log(`${key} type: ${type.name}`);
200+
// other...
201+
};
202+
}
203+
204+
class SomeClass {
205+
@Prop()
206+
public Aprop!: string;
207+
}
208+
```
176209

177210
## 自定义 metadataKey
178211

212+
除能获取类型信息外,常用于自定义 metadataKey,并在合适的时机获取它的值,示例如下:
213+
214+
```ts
215+
function classDecorator(): ClassDecorator {
216+
return target => {
217+
// 在类上定义元数据,key 为 `classMetaData`,value 为 `a`
218+
Reflect.defineMetadata('classMetaData', 'a', target);
219+
};
220+
}
221+
222+
function methodDecorator(): MethodDecorator {
223+
return (target, key, descriptor) => {
224+
// 在类的原型属性 'someMethod' 上定义元数据,key 为 `methodMetaData`,value 为 `b`
225+
Reflect.defineMetadata('methodMetaData', 'b', target, key);
226+
};
227+
}
228+
229+
@classDecorator()
230+
class SomeClass {
231+
@methodDecorator()
232+
someMethod() {}
233+
}
234+
235+
Reflect.getMetadata('classMetaData', SomeClass); // 'a'
236+
Reflect.getMetadata('methodMetaData', new SomeClass(), 'someMethod'); // 'b'
237+
```
238+
179239
## 案例:Format
180240

181241
可以通过 reflect-metadata 包来实现对于元数据的操作。首先我们来看 reflect-metadata 的使用,首先定义使用元数据的函数:
@@ -215,3 +275,31 @@ console.log(g.sayHello());
215275
在上述中,我们在 name 属性的装饰器工厂函数,执行`@Format("Hello, %s")`,返回一个装饰器函数,且该装饰器函数修饰了 Greeter 类的 name 属性,将“name”属性的值写入为"Hello, %s"。然后再 sayHello 方法中,通过 getFormat(this,"name") 取到 formatString 为“Hello,%s”.
216276

217277
## 案例:Angular 2 DI
278+
279+
```ts
280+
type Constructor<T = any> = new (...args: any[]) => T;
281+
282+
const Injectable = (): ClassDecorator => target => {};
283+
284+
class OtherService {
285+
a = 1;
286+
}
287+
288+
@Injectable()
289+
class TestService {
290+
constructor(public readonly otherService: OtherService) {}
291+
292+
testMethod() {
293+
console.log(this.otherService.a);
294+
}
295+
}
296+
297+
const Factory = <T>(target: Constructor<T>): T => {
298+
// 获取所有注入的服务
299+
const providers = Reflect.getMetadata('design:paramtypes', target); // [OtherService]
300+
const args = providers.map((provider: Constructor) => new provider());
301+
return new target(...args);
302+
};
303+
304+
Factory(TestService).testMethod(); // 1
305+
```

0 commit comments

Comments
 (0)