学习目录
- Angular 4 依赖注入教程之一 依赖注入简介
- Angular 4 依赖注入教程之二 组件服务注入
- Angular 4 依赖注入教程之三 ClassProvider的使用
- Angular 4 依赖注入教程之四 FactoryProvider的使用
- Angular 4 依赖注入教程之五 FactoryProvider配置依赖对象
- Angular 4 依赖注入教程之六 Injectable 装饰器
- Angular 4 依赖注入教程之七 ValueProvider的使用
- Angular 4 依赖注入教程之八 InjectToken的使用
本文主要给大家介绍的是关于Angular 4依赖注入之Injectable装饰器的相关内容,分享出来供大家参考学习,下面来看看详细的介绍:
本系列教程的开发环境及开发语言:
- Angular 4 +
- Angular CLI
- TypeScript
基础知识
装饰器是什么
- 它是一个表达式
- 该表达式被执行后,返回一个函数
- 函数的入参分别为 targe、name 和 descriptor
- 执行该函数后,可能返回 descriptor 对象,用于配置 target 对象
装饰器的分类
- 类装饰器 (Class decorators)
- 属性装饰器 (Property decorators)
- 方法装饰器 (Method decorators)
- 参数装饰器 (Parameter decorators)
TypeScript 类装饰器
类装饰器声明:
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void
类装饰器顾名思义,就是用来装饰类的。它接收一个参数:
target: TFunction - 被装饰的类
看完第一眼后,是不是感觉都不好了。没事,我们马上来个例子:
function Greeter(target: Function): void { target.prototype.greet = function (): void { console.log('Hello!'); } } @Greeter class Greeting { constructor() { // 内部实现 } } let myGreeting = new Greeting(); myGreeting.greet(); // console output: 'Hello!';
上面的例子中,我们定义了 Greeter 类装饰器,同时我们使用了 @Greeter 语法,来使用装饰器。
Injectable 类装饰器使用
import { Injectable } from '@angular/core'; @Injectable() class HeroService {}
Injectable 装饰器
在介绍 Injectable 装饰器前,我们先来回顾一下 HeroComponent 组件:
@Component({ selector: 'app-hero', template: ` <ul> <li *ngFor="let hero of heros"> ID: {{hero.id}} - Name: {{hero.name}} </li> </ul> ` }) export class HeroComponent implements OnInit { heros: Array<{ id: number; name: string }>; constructor(private heroService: HeroService, private loggerService: LoggerService) { } ngOnInit() { this.loggerService.log('Fetching heros...'); this.heros = this.heroService.getHeros(); } }
在 HeroComponent 组件的 ngOnInit 生命周期钩子中,我们在获取英雄信息前输出相应的调试信息。其实为了避免在每个应用的组件中都添加 log 语句,我们可以把 log 语句放在 getHeros() 方法内。
更新前 HeroService 服务
export class HeroService { 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: 'Dr IQ' }, { id: 19, name: 'Magma' }, { id: 20, name: 'Tornado' } ]; getHeros() { return this.heros; } }
更新后 HeroService 服务
import { LoggerService } from './logger.service'; export class HeroService { constructor(private loggerService: 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('Fetching heros...'); return this.heros; } }
当以上代码运行后会抛出以下异常信息:
Uncaught Error: Can't resolve all parameters for HeroService: ("htmlcode">export class HeroService { constructor(private loggerService: LoggerService) { } }该构造函数的输入参数是 loggerService 且它的类型是 LoggerService 。在继续深入研究之前,我们来看一下 HeroService 最终生成的 ES5 代码:
var HeroService = (function() { function HeroService(loggerService) { this.loggerService = loggerService; this.heros = [{...}, ...]; } HeroService.prototype.getHeros = function() { this.loggerService.log('Fetching heros...'); return this.heros; }; return HeroService; }());我们发现生成的 ES5 代码中,HeroService 构造函数中是没有包含任何类型信息的,因此 Angular Injector (注入器) 就无法正常工作了。那么要怎么保存 HeroService 类构造函数中参数的类型信息呢?相信你已经想到了答案 — 当然是使用 Injectable 装饰器咯。接下来我们更新一下 HeroService:
import { Injectable } from '@angular/core'; import { LoggerService } from './logger.service'; @Injectable() export class HeroService { // ... }更新完上面的代码,成功保存后,在 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 代码:
var HeroService = (function() { function HeroService(loggerService) { this.loggerService = loggerService; this.heros = [{...}, ...]; } HeroService.prototype.getHeros = function() { this.loggerService.log('Fetching heros...'); return this.heros; }; return HeroService; }()); 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 (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); };我们发现相比未使用 Injectable 装饰器,HeroService 服务生成的 ES5 代码多出了
HeroService = __decorate(...)
这些代码。简单起见,我稍微介绍一下,通过 Injectable 装饰器,在编译时会把 HeroService 服务构造函数中参数的类型信息,通过 Reflect API 保存在window['__core-js_shared__']
对象的内部属性中。当 Injector 创建 HeroService 对象时,会通过 Reflect API 去读取之前已保存的构造函数中参数的类型信息,进而正确的完成实例化操作。
我有话说
@Injectable() 是必须的么?
如果所创建的服务不依赖于其他对象,是可以不用使用 Injectable 类装饰器。但当该服务需要在构造函数中注入依赖对象,就需要使用 Injectable 装饰器。不过比较推荐的做法不管是否有依赖对象,在创建服务时都使用 Injectable 类装饰器。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者使用Angular 4能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。