天天看點

詳談Angular依賴注入(一)

作者:乂舟zz

Angular提供了一個強大的依賴注入(Dependency Injection,簡稱DI)系統,使得元件之間的依賴關系變得清晰,可管理,進而提高了代碼的可讀性和可維護性。今天就來談談Angular依賴注入系統。

一、什麼是依賴注入?

依賴注入是一種設計模式,它處理了對象之間的依賴關系。在沒有依賴注入的情況下,一個對象需要自己建立或者查找它所需要的其他對象。然而,這種方式會導緻對象之間的耦合度增加,當一個對象改變時,可能會影響到其他的對象,進而增加了代碼的複雜度。

相比之下,依賴注入通過将依賴對象的建立和查找工作交給依賴注入系統,使得對象之間的耦合度大大減小。這樣,每個對象隻需要關注自己的職責,而無需關心它的依賴對象如何建立和查找,進而提高了代碼的可讀性和可維護性。

二、依賴注入原理

Angular通過使用裝飾器(Decorator)和中繼資料(Metadata)來實作依賴注入。

首先來看看裝飾器。在Angular中,裝飾器是一種特殊的聲明,它可以修改類、方法、屬性或參數的行為。Angular使用裝飾器來标記和修改類,使得這些類可以被依賴注入系統管理。例如,@Injectable()裝飾器告訴Angular這個類可以被依賴注入系統管理。

‬@Injectable({

providedIn: 'root'

})

export class MyService {

// ...

}

其次來看看中繼資料。中繼資料是關于類、方法、屬性或參數的資料。Angular使用中繼資料來了解如何建立和管理類。例如,providers中繼資料告訴Angular如何建立類的執行個體。

‬@NgModule({

providers: [

MyService

]

})

export class AppModule { }

在這個例子中,providers中繼資料告訴Angular,當需要MyService的執行個體時,應該建立一個MyService的執行個體。

現在我們已經了解了Angular使用裝飾器和中繼資料來實作依賴注入,接下來我們來看看Angular的依賴注入系統是如何工作的。

首先,當Angular需要一個類的執行個體時,它會首先檢查這個類是否有@Injectable()裝飾器。如果有,那麼Angular就會通過調用這個類的構造函數來建立一個新的執行個體。在調用構造函數時,Angular會檢查構造函數的參數。對于每一個參數,Angular會嘗試從依賴注入系統中擷取一個比對的執行個體。

下面這個示例,展示了如何在TypeScript中使用Angular的依賴注入系統:

‬import 'reflect-metadata';

import { ReflectiveInjector, Injectable, Injector } from 'injection-js';

class Http {}

@Injectable()

class Service {

constructor(private http: Http) {}

}

@Injectable()

class Service2 {

constructor(private injector: Injector) {}

getService(): void {

console.log(this.injector.get(Service) instanceof Service);

}

createChildInjector(): void {

const childInjector = ReflectiveInjector.resolveAndCreate([Service], this.injector);

}

}

const injector = ReflectiveInjector.resolveAndCreate([Service, Http]);

console.log(injector.get(Service) instanceof Service);

在這個示例中,Service類依賴于Http類。當Angular需要一個Service的執行個體時,它會通過調用Service的構造函數來建立一個新的執行個體。在調用構造函數時,Angular會嘗試從依賴注入系統中擷取一個Http的執行個體。如果成功,那麼Angular就會将這個Http的執行個體作為參數傳遞給Service的構造函數。

Angular的依賴注入系統還支援多級注入。這意味着一個類可以依賴于其他類,而這些類又可以依賴于其他的類,以此類推。在這種情況下,Angular會遞歸地處理這些依賴關系,直到所有的依賴都被解決。

除此之外,Angular的依賴注入系統還提供了一些進階的特性,比如提供器(providers)、注入令牌(InjectionToken)、可選的依賴項(@Optional())、自我注入(@Self())等等。它們可以讓我們更靈活、更高效地使用Angular的DI系統,使得依賴注入系統更加靈活和強大。

三、提供器(Providers)

提供器是告訴Angular如何建立依賴項的說明。最簡單的提供器就是類提供器,它告訴Angular可以使用new關鍵字來建立依賴項。例如,當我們在@Injectable()裝飾器中設定providedIn: 'root'時,就是告訴Angular要為根注入器建立一個該服務的執行個體。這實際上就是使用了一個類提供器,如下所示:

‬{ provide: MyService, useClass: MyService }

此外,Angular的DI系統還支援其他幾種類型的提供器,如值提供器、工廠提供器和别名提供器,它們可以讓我們更靈活地建立和配置依賴項,我會在後續文章中做詳細介紹。

四、 注入令牌(InjectionToken)

有時,我們可能需要注入一些不是類的值,例如配置對象、基礎類型的值等。為了能夠讓Angular的DI系統識别這些值,我們可以使用InjectionToken來建立一個注入令牌。

‬import { InjectionToken } from '@angular/core';

export const MY_CONFIG_TOKEN = new InjectionToken<string>('My Config');

然後,我們可以在提供器中使用這個令牌來提供一個值:

‬{ provide: MY_CONFIG_TOKEN, useValue: 'My Config Value' }

五、可選的依賴項(@Optional())

在預設情況下,如果Angular的DI系統找不到一個依賴項,就會抛出一個錯誤。但有時,我們可能希望在找不到依賴項時,也能讓應用正常運作。這時,就可以使用@Optional()裝飾器來标記這個依賴項是可選的。

‬constructor(@Optional() private myService: MyService) { }

六、自我注入(@Self())

預設情況下,Angular的DI系統會在目前注入器和其所有父注入器中查找依賴項。如果我們希望Angular隻在目前注入器中查找依賴項,就可以使用@Self()裝飾器。

‬‬constructor(@Self() private myService: MyService) { }

七、跳過自身(@SkipSelf())

相反,如果我們希望Angular跳過目前注入器,隻在其父注入器中查找依賴項,就可以使用@SkipSelf()裝飾器。

‬constructor(@SkipSelf() private myService: MyService) { }

以上就是Angular依賴注入系統的基本介紹,我們可以更好地控制依賴項的建立和注入,進而編寫出更靈活、更可維護的代碼。後續文章會對細節做詳細介紹,歡迎大家持續關注。#前端架構#​#前端面試#​#暑期創作大賽#​

詳談Angular依賴注入(一)

繼續閱讀