Angular装饰器

@Injectable

如果一个 Service 里面需要依赖其他 Service,需要使用 @Injectable 装饰器进行装饰。为了不给自己找麻烦,最好所有 Service 都加上 @Injectable 装饰器,这是一种良好的编码风格。用 @angular/cli 生成的 Service 会自动在头部加上 @Injectable 装饰器,不需要操心。

1
2
3
4
5
6
7
8
9
10
//这里我们把http服务注入到GoodsListService里
import { HttpClient } from '@angular/common/http';

@Injectable({
providedIn: 'root'
})
export class GoodsListService {
constructor(private hc: HttpClient) {
}
}

在配置ModuleInjector时,推荐使用@Injectable()的 providedIn 属性优于 @NgModule() 的 providers 数组,因为使用 @Injectable() 的 providedIn 时,优化工具可以进行摇树优化,从而删除您的应用程序中未使用的服务,以减小捆绑包尺寸。


@Inject

@Injectable与@Inject之间的关系,就像汽车自动挡和手动挡的区别。

1
2
3
4
5
6
7
8
9
10
import { HttpClient } from '@angular/common/http';

@Injectable
export class GoodsListService {
// 在构造函数里手动插入
constructor(
@Inject(HttpClient)private hc
) {
}
}

用 @Inject 和用 @Injectable 最终编译出来的代码是不一样的。用 @Inject 生成的代码多了很多东西,如果出现大量这种代码,最终编译出来的文件体积会变大。

  • 我们可以自己手动用 @Inject 装饰器来让 TypeScript 编译器保留类型元数据,但是一般来说不需要这么干(也就是说,@Inject 装饰器一般是用不到的,除非你想做一些其他的事情)。
  • 保留类型元数据的另一个简便方法是使用 @Injectable 装饰器,@Injectable 并没有什么神奇的作用,它只是告诉 TS 编译器:请生成类型元数据,然后 Angular 在运行时就知道应该注射什么类型的对象了。
  • 这是 TypeScript 强加的一个规则,如果不加 @Injectable 装饰器,TS 编译器会把参数类型元数据丢弃。对于 Angular 中的 Service 来说,最好都加上 @Injectable

@Self

@Self 装饰器来提示注射器,不要向上查找,只在组件自身内部查找依赖。

1
2
3
4
5
6
7
8
9
10
11
//在组件里添加Self服务引用
import { Self } @angular/core

@Component({
providers:[GoodsListService] // 这里需要注入服务,不然会报错
})

// 定义服务
constructor(
@Self() public GoodsListService:GoodsListService
){}

@Optional

用@Optional 装饰器之后,被装饰的服务就变成可选的了。它会沿着Injector Tree向上查找,如果找到了需要注入的类型,就创建实例。
如果没有找到,就会被赋值为null,不会报错!

1
2
3
4
// 我们可以把@Self 和@Optional 结合使用
constructor(
@Self() @Optional() public userListService:UserListService
) { }

这时候不在@Component注入服务,也不会报错了😂😂😂


@SkipSelf

跳过组件自身,然后沿着 Injector Tree 向上查找

1
2
3
4
// 我们可以把@Self 和@Optional 结合使用
constructor(
@SkipSelf() @Optional() public userListService: UserListService
) { }

这样写的含义是:

  • 因为使用了 @SkipSelf 装饰器,所以直接跳过 ChildComponent 组件自身,从 Injector Tree 的父层节点向上进行查找,也就是说,不管 ChildComponent 组件自己有没有配置 UserListService 都不起作用,因为跳过去了;
  • 因为使用了 @Optional 装饰器,如果在父层上面找到了指定的类型,那就创建实例;否则,直接设置为 null,不抛异常。

未完待续