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 相关文章推荐
用js统计用户下载网页所需时间的脚本
Oct 15 Javascript
Jquery ui css framework
Jun 28 Javascript
JavaScript高级程序设计 阅读笔记(四) ECMAScript中的类型转换
Feb 27 Javascript
在js文件中如何获取basePath处理js路径问题
Jul 10 Javascript
当达到输入长度时表单自动切换焦点
Apr 06 Javascript
jQuery实现鼠标划过添加和删除class的方法
Jun 26 Javascript
基于jquery实现导航菜单高亮显示(两种方法)
Aug 23 Javascript
JavaScript获取当前运行脚本文件所在目录的方法
Feb 03 Javascript
浅谈Node.js ORM框架Sequlize之表间关系
Jul 24 Javascript
react的滑动图片验证码组件的示例代码
Feb 27 Javascript
微信小程序select下拉框实现源码
Nov 08 Javascript
JS手写一个自定义Promise操作示例
Mar 16 Javascript
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 数组遍历方法大全(foreach,list,each)
2010/06/30 PHP
通达OA公共代码 php常用检测函数
2011/12/14 PHP
PHP简单实现无限级分类的方法
2016/05/13 PHP
一个简单安全的PHP验证码类、PHP验证码
2016/09/24 PHP
关于ThinkPhp 框架表单验证及ajax验证问题
2017/07/19 PHP
php redis setnx分布式锁简单原理解析
2020/10/23 PHP
基于jquery的DIV随滚动条滚动而滚动的代码
2012/07/20 Javascript
jquery实现textarea输入字符控制(仿微博输入控制字符)
2013/04/26 Javascript
js中点击空白区域时文本框与隐藏层的显示与影藏问题
2013/08/26 Javascript
javascript数组去重方法终极总结
2014/06/05 Javascript
JavaScript实现将UPC转换成ISBN的方法
2015/05/26 Javascript
Jquery简单实现GridView行高亮的方法
2015/06/15 Javascript
javascript返回顶部的按钮实现方法
2016/01/09 Javascript
浅谈几种常用的JS类定义方法
2016/06/08 Javascript
浅谈JS使用[ ]来访问对象属性
2016/09/21 Javascript
vue 监听某个div垂直滚动条下拉到底部的方法
2018/09/15 Javascript
p5.js实现故宫橘猫赏秋图动画
2019/10/23 Javascript
Layui实现数据表格默认全部显示(不要分页)
2019/10/26 Javascript
node.js使用http模块创建服务器和客户端完整示例
2020/02/10 Javascript
js实现简单抽奖功能
2020/11/24 Javascript
Python用GET方法上传文件
2015/03/10 Python
Python多线程编程(七):使用Condition实现复杂同步
2015/04/05 Python
详解python之配置日志的几种方式
2017/05/22 Python
Python的numpy库中将矩阵转换为列表等函数的方法
2018/04/04 Python
python的pip安装以及使用教程
2018/09/18 Python
python 6.7 编写printTable()函数表格打印(完整代码)
2020/03/25 Python
Python运行提示缺少模块问题解决方案
2020/04/02 Python
使用CSS3来代替JS实现交互
2017/08/10 HTML / CSS
Parts Express:音频、视频和扬声器的第一来源
2017/04/25 全球购物
Puccini乌克兰:购买行李箱、女士手袋网上商店
2020/08/06 全球购物
C语言笔试题回忆
2015/04/02 面试题
小班重阳节活动方案
2014/02/08 职场文书
县长群众路线对照检查材料思想汇报
2014/10/02 职场文书
教师查摆问题及整改措施
2014/10/11 职场文书
房屋租赁合同解除协议书
2014/10/11 职场文书
英语通知范文
2015/04/22 职场文书