Angular依賴項注入如今是Angular的核心部分,並容許將依賴項注入到組件或類中編程
依賴注入(DI)是一種技術,在這種技術中,咱們將一個對象的實例提供給另外一個依賴於它的對象。這種技術也稱爲「控制反轉」(IoC)api
IoC — 控制反轉數組
DI — 依賴注入微信
三個原則ide
IOC,是一種設計原則:this
經過將組件(Components)的設置和使用分開,來下降類別或模組之間的耦合度(即,解耦)設計
控制反轉,指實例依賴成員的[控制流程],由主動控制變成被動控制,所以被稱爲控制反轉3d
案例:code
這些過程和iPhone耦合的很緊密,若是小明須要換手機了,那麼那須要在每一個過程當中都將iPhone換爲新手機。這時,就須要控制反轉,咱們再也不主動去得到手機,而是被動的接收一個手機。component
接收手機
咱們發現,過程和具體的一個手機(例如,iPhone)耦合度下降了,能夠很簡單的更改手機的實例。
另外一個例子
咱們去網咖打遊戲,是不可能本身帶遊戲去網咖的,而是網咖都把這些遊戲提供好了
須要的遊戲,不用本身下載,而是網咖提供給你。
==>
須要的依賴實例,不用主動(Active)創建,而是被動(Passive)接收。
簡單來講,A依賴B,但A沒法控制B的建立和銷燬,僅使用B,那麼B的控制權交給C(A之外)處理
- 第一個例子,小明是A,依賴手機B,C能夠是其餘任何給小明手機的人(可能有點牽強)
- 第二個例子,咱們是A,依賴遊戲B,C則是網吧
剛纔那兩個例子中,小明須要手機,咱們須要玩遊戲,那麼有哪些方法可讓咱們被動接收這些東西呢?假設小明是A,手機是B
這個過程就是依賴注入,即A啥都沒幹,就能夠直接使用B,好比咱們啥也不用幹,就能夠直接玩遊戲,真香。
也能夠說,依賴注入是實現控制反轉的一種方式,它們之間有着密切的聯繫
案例一
class Id { static getId(type: string): Id { return new Id() } } class Address { constructor(city, street) { } } class Person { id: Id address: Address constructor(id: Id, address: Address) { this.id = id this.address = address } } // 在某個類當中調用的時候 main() { const id = Id.getId('123') const address = new Address('北京', '北京') const person = new Person(id, address) }
咱們也將依賴提高到了入口處的 main()
當中,可是在當下這種形式中,咱們已經知道若是有新的需求變更,咱們仍是須要去模塊的內部來進行修改,下面咱們就來看看如何在 Angular
當中來解決這個問題的
在 Angular
的依賴注入中主要有三個概念
Injector
,注入者,利用其提供的 API
去建立依賴的實例Provider
,告訴 Injector
如何去建立一個實例(構造這個對象)Object
,建立好的對象,也就是當前所處的模塊或者組件須要的依賴(某種類型的對象,依賴自己也是一種類型)小案例demo
服務 @Injectable() export class StateNewService { constructor() {} getLog() { return '1111' } } 模塊 注入 @NgModule({ providers:[StateNewService] }) 頁面使用 export class TwoComponent implements OnInit { constructor(private states:StateNewService) { console.log(states.getLog()); } }
StateNewService
用做搜索查找的令牌,而後咱們新類StateNewService
,組件可使用它
providers:[{ provide: StateNewService, useClass: StateNewService }] 其實也等價於下面這種寫法 [{ provide:StateNewService, useFactory:()=>new StateNewService() }]
替換當前class
@Injectable() export class CowService { makeNoise() { return 'mooo!'; } } @Injectable() export class TestService { constructor() { } makeNoise() { return '333'; } } providers: [ {provide:TestService,useClass:CowService} ] 使用的時候 constructor( private other: TestService ) { console.log(other.makeNoise()); // mooo!
依賴項是值或者對象或者類表示
服務 @Injectable() export class StateNewService { constructor() {} getLog() { return '1111' } } 模塊 @NgModule({ providers:[ { provide: 'STATE_NEW_SERVICE', useClass: StateNewService }, {provide:'APIURL', useValue: 'http://SomeEndPoint.com/api' }, {provide:'USE_FAKE', useValue: true }, ] }) 使用 export class TwoComponent implements OnInit { constructor( @Inject('STATE_NEW_SERVICE') private states: StateNewService, @Inject('APIURL') private apiURL:string, @Inject('USE_FAKE') private use:boolean ) { console.log(states.getLog()); // two.component.ts:26 1111 console.log(apiURL); // two.component.ts:27 http://SomeEndPoint.com/api console.log(use); // true } }
字符串令牌更易於錯誤鍵入,這使得在大型應用程序中難以跟蹤和維護。
Angular提供了InjectionToken
類,以確保建立了惟一令牌。經過建立類的新實例來建立注入令牌InjectionToken
。
Token
的時候爲了不命名衝突,儘可能避免使用字符串做爲 Token
NgModule
中註冊相關的 provider
Component
中註冊相關的 provider
首先,建立一個單獨的文件,並將其命名爲tokens.ts
InjectionToken
從@angular/core
庫導入。建立的實例InjectionToken
並將其分配給constAPI_URL
import { InjectionToken } from '@angular/core'; export const API_URL= new InjectionToken<string>('');
providers
元數據中註冊值import { API_URL } from './tokens'; providers: [ { provide: API_URL, useValue: 'http://SomeEndPoint.com/api' } ]
直接使用
import { API_URL } from './tokens'; constructor(@Inject(API_URL) private apiURL: string) { }
你能夠把multi:true
打印的時候以前是字符串如今你發現返回的是數組,原理就是相同的token
註冊多個值
providers:[ {provide:API_URL, useValue: 'http://SomeEndPoint.com/api',multi:true }, ]
當咱們給令牌添加第二個token
providers:[ {provide:API_URL, useValue: 'http://SomeEndPoint.com/api1',multi:true }, {provide:API_URL, useValue: 'http://SomeEndPoint.com/api2',multi:true }, ] constructor( @Inject(API_URL) private apiURL:string ) { console.log(apiURL); // ["http://SomeEndPoint.com/api1", "http://SomeEndPoint.com/api2"]
咱們發現若是移除其中一個multi:true
,咱們會發現打印的時候報錯
若是發現若是兩個都移除multi:true
,咱們會發現打印的是api2
,下面的會把上面的替換掉