首頁 >web前端 >js教程 >Angular 2組件和提供商:類,工廠和價值觀

Angular 2組件和提供商:類,工廠和價值觀

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌原創
2025-02-15 12:07:12635瀏覽

Angular 2 Components and Providers: Classes, Factories & Values

核心要點

  • Angular 2 組件能夠使用提供者 (providers),提供者是一組可注入的對象,組件可以使用它們。提供者是 Angular 2 依賴注入 (DI) 系統的基礎。
  • 提供者可分為三種類型:類提供者、工廠提供者和值提供者。類提供者生成類的實例,工廠提供者生成指定函數的返回值,值提供者直接返回其值。
  • Angular 2 的 DI 系統允許註冊類、函數或值(稱為提供者),解決提供者之間的依賴關係,使提供者的結果可在代碼中使用,並維護注入器的層次結構。
  • Angular 的注入器只創建一次類提供者的實例,並將其緩存,只要使用相同的提供者,後續每次注入都會收到相同的實例。此功能使您可以靈活地控制任何一個提供者生成的結果,以及我們是否使用單個實例或多個實例。
  • Angular 2 允許使用與實際提供者關聯的鍵(稱為“令牌”)註冊提供者。此功能對於單元測試很有用,在單元測試中,可以替換一個不會進行服務器調用的模擬類,而無需更改組件代碼。

前文探討瞭如何使用 @Input@Output 註解將數據傳入和傳出組件。本文將介紹 Angular 2 組件的另一個基本方面——它們使用 提供者 的能力。

您可能在組件配置屬性列表中看到過“提供者”,並且您可能意識到它們允許您定義一組可用於組件的可注入對象。這很好,但當然會引出一個問題,“什麼是提供者?”

回答這個問題需要深入探討 Angular 2 的依賴注入 (DI) 系統。我們可能會在以後的博文中專門介紹DI,但Pascal Precht 的一系列文章對此進行了很好的介紹,從這裡開始:https://www.php.cn/link/f7f3bfce09a3008d185e1775549ec2d2 DI 和Angular 2 的DI 系統(如Pascal 的文章中所述),但簡而言之,DI 系統負責:

  • 註冊類、函數或值。在依賴注入的上下文中,這些項目被稱為“提供者”,因為它們會產生結果。例如,類用於提供或產生實例。 (有關提供者類型的更多詳細信息,請參見下文。)
  • 解決提供者之間的依賴關係——例如,如果一個提供者需要另一個提供者。
  • 當我們請求提供者結果時,使提供者的結果可在代碼中使用。此過程(使提供者結果可用於代碼塊)稱為“注入它”。注入提供者結果的代碼邏輯上稱為“注入器”。
  • 維護注入器的層次結構,以便如果組件請求其註入器中不可用的提供者的提供者結果,DI 將向上搜索注入器的層次結構。

在之前的文章中,我們包含了一個圖表,顯示組件形成以根組件開頭的層次結構。讓我們補充該圖表以包含注入器及其註冊的資源(提供者):

Angular 2 Components and Providers: Classes, Factories & Values

圖 1:每個組件都有自己的注入器,用於註冊提供者。注入器創建子注入器,對提供者的請求從本地註入器開始,並向上搜索注入器層次結構。

從上面我們可以看出,雖然組件形成了一個向下定向圖,但它們相關的注入器具有雙向關係:父注入器創建子注入器(向下),當請求提供者時,如果組件自己的注入器中找不到請求的提供者,Angular 2 將向上搜索父注入器(向上)。這意味著較低級別具有相同標識符的提供者將遮蓋(隱藏)較高級別具有相同名稱的提供者。

什麼是提供者?

那麼,注入器在每個級別註冊的這些“提供者”是什麼呢?實際上很簡單:提供者是 Angular 用於提供(產生、生成)我們想要使用的資源或 JavaScript“事物”:

  • 類提供者生成/提供類的實例。
  • 工廠提供者生成/提供運行指定函數時返回的內容。
  • 值提供者不需要像前兩者那樣採取操作來提供結果,它只返回其值。

不幸的是,術語“提供者”有時既指類、函數或值,也指提供者產生的事物——類實例、函數的返回值或返回值。

讓我們看看如何通過使用 MyClass(一個簡單的類,將生成我們想要在應用程序中使用的實例)創建類提供者來向組件添加提供者。

Angular 2 Components and Providers: Classes, Factories & Values

圖 2:具有四個屬性的簡單類。 (代碼屏幕截圖來自 Visual Studio Code)

好了,這就是類。現在讓我們指示 Angular 使用它註冊類提供者,以便我們可以要求依賴注入系統提供一個實例供我們在代碼中使用。我們將創建一個組件 ProvDemo_01.ts,它將用作應用程序的根組件。我們在 bootstrap.ts 中加載此組件並啟動我們的應用程序:

Angular 2 Components and Providers: Classes, Factories & Values

圖 3:啟動應用程序的 bootstrap.ts 文件,它實例化根組件。

如果上面的內容沒有意義,請查看我們之前的文章,該文章介紹了構建簡單的 Angular 2 應用程序的過程。我們的根組件稱為 ProvDemo,存儲庫包含幾個不同版本的該組件。您可以通過更新上面導入 ProvDemo 的行來更改顯示的版本。我們的根組件的第一個版本如下所示:

Angular 2 Components and Providers: Classes, Factories & Values

圖 4:導入 MyClassCompDemo,將其添加到 providers 數組中,並在構造函數參數中將其用作類型。

向此組件添加 MyClass 提供者很簡單:

  • 導入 MyClass
  • 將其添加到 @Componentproviders 屬性
  • 向構造函數添加類型為“MyClass”的參數

在幕後,當 Angular 實例化組件時,DI 系統會為組件創建一個注入器,該注入器註冊 MyClass 提供者。然後,Angular 會看到在構造函數的參數列表中指定的MyClass 類型,並查找新註冊的MyClass 提供者,並使用它來生成一個實例,然後將其分配給“myClass”(初始小寫“m”)。

查找 MyClass 提供者和生成要分配給“myClass”的實例的過程都是 Angular 完成的。它利用 TypeScript 語法來了解要搜索的類型,但 Angular 的注入器負責查找和返回 MyClass 實例。

鑑於上述情況,您可能會得出結論,Angular 會獲取“providers”數組中的類列表,並創建一個簡單的註冊表來檢索該類。但是,為了提高靈活性,存在一個細微的調整。需要“調整”的一個主要原因是幫助我們編寫組件的單元測試,這些組件具有我們不想在測試環境中使用的提供者。對於 MyClass,沒有太多理由不使用真實的東西,但是如果 MyClass 調用服務器來檢索數據,我們可能不想或無法在測試環境中這樣做。為了解決這個問題,我們需要能夠在 ProvDemo 中替換不會進行服務器調用的模擬 MyClass

我們如何進行替換?我們是否需要遍歷所有代碼並將每個 MyClass 引用更改為 MyClassMock?這效率不高,並且是編寫測試的糟糕模式。

我們需要在不更改 ProvDemo 組件代碼的情況下替換提供者實現。為了實現這一點,當 Angular 註冊提供者時,它會設置一個映射,以將鍵(稱為“令牌”)與實際提供者相關聯。在上面的示例中,令牌和提供者是同一事物:MyClass。將 MyClass 添加到 @Component 裝飾器中的 providers 屬性是以下內容的簡寫:

<code>providers: [ provide(MyClass, {useClass: MyClass} ]</code>

這意味著“使用MyClass 作為令牌(鍵)來查找提供者,並將提供者設置為MyClass,以便當我們請求提供者時,依賴注入系統會返回MyClass 實例” 。我們大多數人都習慣於將鍵視為數字或字符串。但在這種情況下,令牌(鍵)是類本身。我們也可以使用字符串作為令牌來註冊提供者,如下所示:

<code>providers: [ provide("aStringNameForMyClass", {useClass: MyClass} ]</code>

那麼,這如何幫助我們進行測試呢?這意味著在測試環境中,我們可以覆蓋提供者註冊,有效地執行以下操作:

<code>provide(MyClass, {useClass: MyClassMock})
</code>

這會將令牌(鍵)MyClass 與類提供者 MyClassMock 關聯起來。當我們的代碼要求 DI 系統在測試中註入 MyClass 時,我們會得到 MyClassMock 的實例,它可以偽造數據調用。最終效果是所有代碼保持不變,我們不必擔心單元測試是否會調用在測試環境中可能不存在的服務器。

注入非類提供者

在上面,我們通過編寫以下代碼將類提供者實例注入到構造函數中:

<code>constructor( myClass: MyClass ) {...}
</code>

TypeScript 允許我們指定 myClass 參數需要是 MyClass 類型,而 DI 系統會完成工作,為我們提供 MyClass 實例。

但是,如果我們使用字符串令牌而不是類,我們如何告訴 Angular 注入我們的提供者結果呢?讓我們編輯 bootstrap.ts 文件以添加新的值提供者並使用字符串令牌註冊它。請記住,值提供者是一種返回與令牌關聯的值的提供者類型。在上面的示例中,我們告訴Angular 通過添加到@Componentproviders 屬性來註冊提供者,但我們也可以通過將它們傳遞到引導函數中來註冊提供者(可以將相同的內容添加到providers 屬性):

Angular 2 Components and Providers: Classes, Factories & Values

圖 5:添加了值提供者的 bootstrap.ts

在這裡,我們通過調用provide 函數並傳入字符串令牌(“SECURITY_KEY”)和一個對象來添加提供者,該對象指定我們想要創建一個值提供者以及提供者本身——在本例中是一個簡單值。現在,我們想將值提供者生成的值注入到我們的構造函數中,但這行不通……

<code>providers: [ provide(MyClass, {useClass: MyClass} ]</code>

這是因為“SECURITY_KEY”不是類型。為了使能夠注入具有非類令牌的提供者成為可能,Angular 為我們提供了 @Inject 參數裝飾器。與所有其他裝飾器一樣,我們需要導入它,然後我們使用它來告訴 Angular 注入與我們的字符串令牌關聯的提供者。為此,我們調整 create ProvDemo_02.ts

Angular 2 Components and Providers: Classes, Factories & Values

圖 6:導入“Inject”裝飾器並使用它來注入使用字符串令牌標識的值提供者。

我們可以使用相同的語法來注入 MyClass 提供者:

<code>providers: [ provide("aStringNameForMyClass", {useClass: MyClass} ]</code>

好了,我們已經了解瞭如何註冊和使用提供者,但讓我們進一步了解提供者返回的內容。

提供者和單例

正如我們在上面看到的,提供者負責生成要注入的事物。類提供者會生成一個實例,然後注入該實例。但是,重要的是要理解,每次注入類提供者結果時,您都不會獲得一個新實例。相反,DI 系統會生成一次實例,將其緩存,並且只要您使用相同的提供者,後續每次注入都會收到相同的實例。

最後一點很重要,因為每個組件都有自己的注入器及其自己的註冊提供者。 MyClass 具有設置為當前時間(以毫秒為單位)的時間屬性和一個隨機數,以幫助我們查看我們每次是否獲得相同的實例。我們將向應用程序添加一個 ChildComp 組件。

Angular 2 Components and Providers: Classes, Factories & Values

圖 7:將 MyClass 注入到構造函數中的 ChildComp

請注意,我們導入 MyClass 並使用它來設置構造函數參數列表中的類型。重要提示:導入的 MyClassChildComp 中的唯一用途是作為 DI 系統用來查找註冊提供者的令牌。 因為 ChildComp 沒有使用該令牌註冊自己的提供者,所以 Angular 會向上查找注入器層次結構以找到一個。為了使這能夠工作,我們需要將 ChildComp 添加到 ProvDemo 組件:

Angular 2 Components and Providers: Classes, Factories & Values

圖 8:向模板中添加了 ChildCompProvDemo

我們導入 ChildComp,向 @Component 添加 directives 屬性以告訴 ProvDemo 我們將使用 ChildComp 組件,並將 ChildComp 元素添加到模板。當應用程序運行時,控制台輸出顯示 ProvDemoChildComp 都收到相同的 MyClass 實例:

<code>providers: [ provide(MyClass, {useClass: MyClass} ]</code>

現在讓我們更改 ChildComp 以向其註入器添加 MyClass 提供者:

Angular 2 Components and Providers: Classes, Factories & Values

圖 9:定義了自己的 MyClass 提供者的 ParentComp

我們唯一更改的是向 @Component 註解添加 providers 屬性。當然,我們可以看到創建了兩個不同的 MyClass 實例:

<code>providers: [ provide("aStringNameForMyClass", {useClass: MyClass} ]</code>

Angular 的此功能為任何一個提供者生成的結果以及我們是否要使用單個實例或多個實例提供了很大的靈活性。例如,您可以將組件放在重複器中,以便多次生成組件。如果此重複組件註冊自己的提供者,則每個組件都會獲得唯一的提供者。但是,如果您只在父組件中註冊提供者,則每個重複實例都會共享父組件的提供者。

總結

在本文中,我們定義了什麼是提供者,並介紹了三種不同類型的提供者。然後,我們研究瞭如何為組件註冊提供者以及如何將提供者生成的結果注入到組件中。我們還研究了 Angular 如何使用注入器層次結構來查找請求的提供者。 Angular 為您提供了更多關於依賴注入系統如何工作以及在何處查找提供者的控制,但以上內容應該可以幫助您開始在 Angular 2 應用程序中創建和使用提供者。

關於 Angular 2 組件、提供者、類、工廠和值的常見問題 (FAQ)

類和工廠在 Angular 2 中有什麼區別?

在 Angular 2 中,類是創建對象的藍圖。它封裝了數據和操作該數據的函數。另一方面,工廠是一種用於創建對象的模式。在 Angular 2 中,工廠用於創建和配置沒有明確類來表示的服務或值。工廠提供了一種根據上下文或配置生成不同類實例的方法。

組件和提供者如何在 Angular 2 中交互?

在 Angular 2 中,組件和提供者協同工作以創建動態且交互式的用戶界面。組件是 Angular 應用程序的構建塊,而提供者用於創建組件可以使用的服務。提供者允許組件共享數據和功能,從而更易於維護和更新應用程序。

值在 Angular 2 中的作用是什麼?

Angular 2 中的值用於向應用程序的其他部分提供配置信息。它們可以注入到控制器、服務和工廠中,允許在運行時配置應用程序的這些部分。這使應用程序更靈活,也更易於測試。

如何在 Angular 2 中綁定類?

Angular 2 中的類綁定是一種動態地向元素添加和刪除 CSS 類的方法。您可以將類綁定到表達式,當該表達式計算結果為 true 時,該類將添加到元素。如果表達式的計算結果為 false,則該類將被刪除。這允許您創建動態且交互式的用戶界面。

在 Angular 2 的上下文中,API 是什麼?

在 Angular 2 的上下文中,API(應用程序編程接口)是一組用於構建和交互軟件應用程序的規則和協議。 Angular 2 提供了一個豐富的 API,允許開發人員使用更少的代碼和精力創建複雜的應用程序。 Angular 2 API 包括用於創建組件、服務、指令、管道等的特性。

如何在 Angular 2 中使用工廠?

要在 Angular 2 中使用工廠,您首先需要定義它。這是通過創建一個返回您希望工廠生成的對象的函數來完成的。然後,您可以使用 .factory 方法將此工廠與 Angular 模塊註冊。註冊工廠後,您可以將其註入到應用程序的其他部分,例如控制器和服務。

如何在 Angular 2 中創建組件?

在 Angular 2 中創建組件涉及定義一個類並使用 @Component 裝飾器對其進行裝飾。 @Component 裝飾器告訴 Angular 該類是一個組件,並提供元數據,這些元數據確定如何在運行時處理、實例化和使用該組件。

如何在 Angular 2 中使用提供者?

Angular 2 中的提供者用於創建和向應用程序部分提供服務。要使用提供者,您首先需要將其與 Angular 模塊註冊。註冊後,可以將提供者註入到組件、其他服務甚至其他提供者中。

如何在 Angular 2 中創建服務?

在 Angular 2 中創建服務涉及定義一個類,該類封裝了服務提供的數和函數。然後,此類將使用 @Injectable 裝飾器進行裝飾,該裝飾器告訴 Angular 該類是一個服務,可以注入到應用程序的其他部分。

如何在 Angular 2 中使用值?

Angular 2 中的值用於向應用程序的其他部分提供配置信息。要使用值,您首先需要將其與 Angular 模塊註冊。註冊後,可以將值注入到控制器、服務和工廠中。

以上是Angular 2組件和提供商:類,工廠和價值觀的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn