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

网友投稿 239 2023-05-10


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

学习目录

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 = (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: `

ID: {{hero.id}} - Name: {{hero.name}}

`

})

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' },

{ ihttp://d: 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 DhOkBlj类生成的 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能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:用类怎么实现接口(类怎样实现接口)
下一篇:老生常谈反射之Class类的使用(必看篇)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~