Angular 4依赖注入学习教程之Injectable装饰器(六)
学习目录
- Angular4依赖注入教程之一依赖注入简介
- Angular4依赖注入教程之二组件服务注入
- Angular4依赖注入教程之三ClassProvider的使用
- Angular4依赖注入教程之四FactoryProvider的使用
- Angular4依赖注入教程之五FactoryProvider配置依赖对象
- Angular4依赖注入教程之六Injectable装饰器
- Angular4依赖注入教程之七ValueProvider的使用
- Angular4依赖注入教程之八InjectToken的使用
本文主要给大家介绍的是关于Angular4依赖注入之Injectable装饰器的相关内容,分享出来供大家参考学习,下面来看看详细的介绍:
本系列教程的开发环境及开发语言:
- Angular4+
- AngularCLI
- TypeScript
基础知识
装饰器是什么
- 它是一个表达式
- 该表达式被执行后,返回一个函数
- 函数的入参分别为targe、name和descriptor
- 执行该函数后,可能返回descriptor对象,用于配置target对象
装饰器的分类
- 类装饰器(Classdecorators)
- 属性装饰器(Propertydecorators)
- 方法装饰器(Methoddecorators)
- 参数装饰器(Parameterdecorators)
TypeScript类装饰器
类装饰器声明:
declaretypeClassDecorator=(target:TFunction)=> TFunction|void
类装饰器顾名思义,就是用来装饰类的。它接收一个参数:
target:TFunction-被装饰的类
看完第一眼后,是不是感觉都不好了。没事,我们马上来个例子:
functionGreeter(target:Function):void{
target.prototype.greet=function():void{
console.log('Hello!');
}
}
@Greeter
classGreeting{
constructor(){//内部实现}
}
letmyGreeting=newGreeting();
myGreeting.greet();//consoleoutput:'Hello!';
上面的例子中,我们定义了Greeter类装饰器,同时我们使用了@Greeter语法,来使用装饰器。
Injectable类装饰器使用
import{Injectable}from'@angular/core';
@Injectable()
classHeroService{}
Injectable装饰器
在介绍Injectable装饰器前,我们先来回顾一下HeroComponent组件:
@Component({
selector:'app-hero',
template:`
- ID:{{hero.id}}-Name:{{hero.name}}
在HeroComponent组件的ngOnInit生命周期钩子中,我们在获取英雄信息前输出相应的调试信息。其实为了避免在每个应用的组件中都添加log语句,我们可以把log语句放在getHeros()方法内。
更新前HeroService服务
exportclassHeroService{
heros:Array<{id:number;name:string}>=[
{id:11,name:'Mr.Nice'},
{id:12,name:'Narco'},
{id:13,name:'Bombasto'},
{id:14,name:'Celeritas'},
{id:15,name:'Magneta'},
{id:16,name:'RubberMan'},
{id:17,name:'Dynama'},
{id:18,name:'DrIQ'},
{id:19,name:'Magma'},
{id:20,name:'Tornado'}
];
getHeros(){
returnthis.heros;
}
}
更新后HeroService服务
import{LoggerService}from'./logger.service';
exportclassHeroService{
constructor(privateloggerService:LoggerService){}
heros:Array<{id:number;name:string}>=[
{id:11,name:'Mr.Nice'},
{id:12,name:'Narco'},
{id:13,name:'Bombasto'},
{id:14,name:'Celeritas'},
{id:15,name:'Magneta'}
];
getHeros(){
this.loggerService.log('Fetchingheros...');
returnthis.heros;
}
}
当以上代码运行后会抛出以下异常信息:
UncaughtError:Can'tresolveallparametersforHeroService:(?).
上面异常信息说明无法解析HeroService的所有参数,而HeroService服务的构造函数如下:
exportclassHeroService{
constructor(privateloggerService:LoggerService){}
}
该构造函数的输入参数是loggerService且它的类型是LoggerService。在继续深入研究之前,我们来看一下HeroService最终生成的ES5代码:
varHeroService=(function(){
functionHeroService(loggerService){
this.loggerService=loggerService;
this.heros=[{...},...];
}
HeroService.prototype.getHeros=function(){
this.loggerService.log('Fetchingheros...');
returnthis.heros;
};
returnHeroService;
}());
我们发现生成的ES5代码中,HeroService构造函数中是没有包含任何类型信息的,因此AngularInjector(注入器)就无法正常工作了。那么要怎么保存HeroService类构造函数中参数的类型信息呢?相信你已经想到了答案—当然是使用Injectable装饰器咯。接下来我们更新一下HeroService:
import{Injectable}from'@angular/core';
import{LoggerService}from'./logger.service';
@Injectable()
exportclassHeroService{
//...
}
更新完上面的代码,成功保存后,在http://localhost:4200/页面,你将看到熟悉的"身影":
ID:11-Name:Mr.Nice ID:12-Name:Narco ID:13-Name:Bombasto ID:14-Name:Celeritas ID:15-Name:Magneta
现在我们再来看一下HeroService类生成的ES5代码:
varHeroService=(function(){
functionHeroService(loggerService){
this.loggerService=loggerService;
this.heros=[{...},...];
}
HeroService.prototype.getHeros=function(){
this.loggerService.log('Fetchingheros...');
returnthis.heros;
};
returnHeroService;
}());
HeroService=__decorate([__webpack_require__.i(
__WEBPACK_IMPORTED_MODULE_0__angular_core__["c"/*Injectable*/
])(),__metadata("design:paramtypes",...)],HeroService);
__decorate函数
var__decorate=(this&&this.__decorate)||function(decorators,target,key,desc){...};
__metadata函数
var__metadata=(this&&this.__metadata)||function(k,v){
if(typeofReflect==="object"&&typeofReflect.metadata==="function")
returnReflect.metadata(k,v);
};
我们发现相比未使用Injectable装饰器,HeroService服务生成的ES5代码多出了HeroService=__decorate(...)这些代码。简单起见,我稍微介绍一下,通过Injectable装饰器,在编译时会把HeroService服务构造函数中参数的类型信息,通过ReflectAPI保存在window['__core-js_shared__']对象的内部属性中。当Injector创建HeroService对象时,会通过ReflectAPI去读取之前已保存的构造函数中参数的类型信息,进而正确的完成实例化操作。
我有话说
@Injectable()是必须的么?
如果所创建的服务不依赖于其他对象,是可以不用使用Injectable类装饰器。但当该服务需要在构造函数中注入依赖对象,就需要使用Injectable装饰器。不过比较推荐的做法不管是否有依赖对象,在创建服务时都使用Injectable类装饰器。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者使用Angular4能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。