Angular 4依赖注入学习教程之Injectable装饰器(六)


Posted in Javascript onJune 04, 2017

学习目录

  • 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: (?).

上面异常信息说明无法解析 HeroService 的所有参数,而 HeroService 服务的构造函数如下:

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能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JavaScript 异步调用框架 (Part 2 - 用例设计)
Aug 03 Javascript
JavaScript表达式:URL 协议介绍
Mar 10 Javascript
JS实现Enter键跳转及控件获得焦点
Aug 12 Javascript
jQuery过滤选择器:not()方法使用介绍
Apr 20 Javascript
禁用Enter键表单自动提交实现代码
May 22 Javascript
探寻JavaScript中this指针指向
Apr 23 Javascript
Bootstrap标签页(Tab)插件使用方法
Mar 21 Javascript
小程序如何自主实现拦截器的示例代码
Nov 04 Javascript
Node.JS发送http请求批量检查文件中的网页地址、服务是否有效可用
Nov 20 Javascript
Jquery 获取相同NAME 或者id删除行操作
Aug 24 jQuery
ES6学习教程之Promise用法详解
Nov 22 Javascript
vue router 动态路由清除方式
May 25 Vue.js
Angular 4依赖注入学习教程之FactoryProvider配置依赖对象(五)
Jun 04 #Javascript
JavaScript基础之this详解
Jun 04 #Javascript
Angular 4 依赖注入学习教程之FactoryProvider的使用(四)
Jun 04 #Javascript
Angular 4依赖注入学习教程之ClassProvider的使用(三)
Jun 04 #Javascript
Angular 4依赖注入学习教程之组件服务注入(二)
Jun 04 #Javascript
JavaScript箭头(arrow)函数详解
Jun 04 #Javascript
Angular 4依赖注入学习教程之简介(一)
Jun 04 #Javascript
You might like
php zip文件解压类代码
2009/12/02 PHP
PHP使用DES进行加密与解密的方法详解
2013/06/06 PHP
thinkphp autoload 命名空间自定义 namespace
2015/07/17 PHP
利用Fix Rss Feeds插件修复WordPress的Feed显示错误
2015/12/19 PHP
thinkPHP5 tablib标签库自定义方法详解
2017/05/10 PHP
php注册审核重点解析(数据访问)
2017/05/23 PHP
JavaScript中获取未知对象属性的代码
2011/04/27 Javascript
自动最大化窗口的Javascript代码
2013/05/22 Javascript
[原创]Javascript 实现广告后加载 可加载百度谷歌联盟广告
2016/05/11 Javascript
jQuery的Read()方法代替原生JS详解
2016/11/08 Javascript
Jquery 整理元素选取、常用方法一览表
2016/11/26 Javascript
Angular中$broadcast和$emit的使用方法详解
2017/05/22 Javascript
Vue组件化通讯的实例代码
2017/06/23 Javascript
快速解决vue在ios端下点击响应延时的问题
2018/08/27 Javascript
微信小程序ibeacon三点定位详解
2018/10/31 Javascript
详解vuex 渐进式教程实例代码
2018/11/27 Javascript
VueX模块的具体使用(小白教程)
2020/06/05 Javascript
[01:55]2014DOTA2国际邀请赛快报:国土生病 紧急去医院治疗
2014/07/10 DOTA
[04:45]DOTA2-DPC中国联赛正赛 iG vs LBZS 赛后选手采访
2021/03/11 DOTA
Python实现3行代码解简单的一元一次方程
2014/08/18 Python
Python的Django框架中设置日期和字段可选的方法
2015/07/17 Python
python实现感知器算法详解
2017/12/19 Python
使用Pandas的Series方法绘制图像教程
2019/12/04 Python
python suds访问webservice服务实现
2020/06/26 Python
利用python汇总统计多张Excel
2020/09/22 Python
python 对xml解析的示例
2021/02/27 Python
CSS3中:nth-child和:nth-of-type的区别深入理解
2014/03/10 HTML / CSS
Omio西班牙:全欧洲低价大巴、火车和航班搜索和比价
2017/02/11 全球购物
幼儿园优秀教师事迹
2014/02/13 职场文书
建筑安全员岗位职责
2014/03/13 职场文书
《猴子种果树》教学反思
2014/04/26 职场文书
乡党政领导班子群众路线教育实践活动个人对照检查材料
2014/09/20 职场文书
学生保证书格式
2015/02/27 职场文书
社区志愿者服务心得体会
2016/01/22 职场文书
《曾国藩家书》读后感——读家书,立家风
2019/08/21 职场文书
HTML+VUE分页实现炫酷物联网大屏功能
2021/05/27 Vue.js