前端的技術的極速發展,對前端同學來說也是一個不小的挑戰,有各種各樣的東西需要學,在開發過程中經常會被後端同學嘲諷,對於前端來講根本就不存在類的概念,很多時候需要把大量的業務程式碼堆積在頁面或者元件中,使元件和頁面變得特別的臃腫,一旦業務邏輯複雜的情況下,及時元件化做的很好,仍然避免不了難以維護。
之所以會被後端同學嘲諷,一基礎掌握不紮實,對前端理解不到位,二缺乏物件導向思想,三對業務與基礎傻傻分不清楚。ECMAScript 2015
與Type Script
的推出,提出了一個很重要的概念就是class
(類)的概念。在沒有class
之前為了前端能夠有類的概念,一直都是使用建構函式模擬類的概念,通過原型完成繼承。
雖然前端提出了很多概念(模組化,元件化...),個人覺得物件導向的應用是前端對於專案以及整體架構來講是一件利器,程式碼結構好與壞與物件導向有一定的關係,但不是全部。不過我們可以藉助計算機領域的一些優秀的程式設計理念來一定程度上解決這些問題,接下來簡單的說下依賴注入(控制反轉)。
什麼是依賴注入
依賴注入一般指控制反轉,是物件導向程式設計中的一種設計原則,可以用來減低計算機程式碼之間的耦合度。其中最常見的方式叫做依賴注入,還有一種方式叫依賴查詢
。通過控制反轉,物件在被建立的時候,由一個調控系統內所有物件的外界實體將其所依賴的物件的引用傳遞給它。也可以說,依賴被注入到物件中。
從上面的描述中可以發現,依賴注入發生在2個或兩個以上類,比如現在有兩個類A
與B
類,如果A
是基礎類存在的話,B
做為業務類存在,B
則會依賴於A
,上面有一句話很重要由一個調控系統內所有物件的外界實體將其所依賴的物件的引用傳遞給它
,個人理解,在B
類中使用A
類的例項,而不是繼承A
類。
對物件導向瞭解的同學應該瞭解,物件導向7大原則:
- 單一職責
- 開閉原則
- 里氏替換
- 依賴倒置
- 介面隔離
- 迪米特法則
- 組合聚合複用原則
詳細解釋參照:物件導向之七大基本原則(javaScript)
然而使用依賴注入的事為了降低程式碼的耦合程度,提高程式碼的可擴充性。以上都是一些物件導向的思想,我們參考一下以上最重要的幾個原則,層模組不應該依賴低層模組。兩個都應該依賴抽象,抽象不應該依賴具體實現,具體實現應該依賴抽象。
// 球隊資訊不依賴具體實現
// 面向介面即面向抽象程式設計
class Fruit {
constructor(name) {
this.name = name
}
}
class Tropical {
// 此處的引數,是teamInfo的一個例項,不直接依賴具體的例項
// 面向抽象
constructor(fruit) {
this.fruit = fruit;
}
info() {
console.log(this.fruit.name)
}
}
// 將依賴關係放到此處來管理,控制權也放到此處
// Tropical和Fruit之間不再有直接依賴
// 原本直接掌握Fruit控制權的Tropical不再直接依賴
// 將依賴控制,落在此處(第三方模組專門管理)即為控制反轉
var ym = new Tropical(new Fruit('香蕉'))
ym.info()
var kobe = new Tropical(new Fruit('菠蘿'))
kobe.info()
依賴注入的作用
初始化被依賴的模組
如果不通過依賴注入模式來初始化被依賴的模組,那麼就要依賴模組自己去初始化了
那麼問題來了:依賴模組就耦合了被依賴模組的初始化資訊了
注入到依賴模組中
被依賴模組已經被其他管理器初始化了,那麼依賴模組要怎麼獲取這個模組呢?
有兩種方式:
- 自己去問
- 別人主動給你
沒用依賴注入模式的話是1,用了之後就是2
想想,你需要某個東西的時候,你去找別人要,你需要提供別人什麼資訊?最簡單的就是那個東西叫什麼,即你需要提供一個名稱。所以,方式1的問題是:依賴模組耦合了被依賴模組的名稱
還有那個別人
而方式2解決了這個問題,讓依賴模組只依賴需要的模組的介面。
依賴注入的優點
依賴注入降低了依賴和被依賴型別間的耦合,在修改被依賴的型別實現時,不需要修改依賴型別的實現,同時,對於依賴型別的測試。依賴注入方式,可以將程式碼耦合性降到最低,而且各個模組擴充不會互相影響,
- 實現資料訪問層,也就是前端你的資料請求層
- 模組與介面重構,依賴注入背後的一個核心思想是單一功能原則,這意味著這些物件在系統的任何地方都可以重用。
- 隨時增加單元測試,把功能封裝到整個物件裡面會導致自動測試困難或者不可能。將模組和介面與特定物件隔離,以這種方式重構可以執行更先進的單元測試。
Vue中使用
上面寫的例子也只是對依賴注入見單的使用,在專案過程中往往就不是這麼簡單了,肯定不會向例子這麼簡單,而是很複雜很龐大的一個專案。專案中分為各種各樣的模組,這種情況又改如何處理?在JavaScript
中常見的就是依賴注入。從名字上理解,所謂依賴注入,即元件之間的依賴關係由容器在執行期決定,形象的來說,即由容器動態的將某種依賴關係注入到元件之中。
前端專案中並不像後端一樣,各種各樣的類,雖然前端可以寫class
,若是React
專案的話,還會好很多,由於其框架使用,全部是基於class
但是在vue
專案中,又應該怎麼具體體現呢?頁面中的業務也是可以作為類存在最終注入到Vue
頁面中,最終完成業務邏輯。
通過依賴注入到底想要達到到什麼效果呢,依賴注入最終想要達成的效果則是,頁面的表現與業務相脫離,從本質上來說,頁面的展現形式與業務邏輯其實沒有根本聯絡的。若使用這種依賴注入的形式,則可以輕鬆的把業務和頁面表現分離開,頁面更加的專注於展示,而所注入的東西則更加的專注於業務的處理。專案也則會變得容易維護。
index.vue
<template>
<div>
<el-button @click="getList"
:loadding="loadding">獲取表格資料</el-button>
<ul>
<li v-for="(item,index) of list"
:key="index">{{item}}</li>
</ul>
</div>
</template>
<script>
import operation from "@/business/index/Operation.js";
export default {
data() {
return {
list: [],
query:{},
loadding:false
}
},
methods:{
async getList(){
let {query} = this;
this.loadding = true;
try{
this.list = await operation.getData.call(this,query);
}catch(error){
console.log(error)
}
this.loadding =false;
}
}
}
</script>
<style>
@import "@/style/index.vue";
</style>
operations.js
import request from "@/api/errorList/index.js";
class Operation {
async getData(query){
// this 指向Vue例項
try {
let res = await request.getErrorList(query);
let {list} = res;
// 這裡可以對資料進行二次處理
// 寫一些其他業務
Promise.resolve(list);
}catch(error){
Promise.reject(error);
}
}
};
export default new Operation();
上面也是在專案中的一個簡單的應用,使頁面表現資料請求與資料處理,業務相脫離,讓專案變得更加容易維護。
控制反轉這裡控制權從使用者本身轉移到第三方容器上,而非是轉移到被呼叫者上,這裡需要明確不要疑惑。控制反轉是一種思想,依賴注入是一種設計模式。
依賴注入最終想要達到的目的,首先得為模組依賴提供抽象的介面,下來應該能夠註冊依賴關係
在註冊這個依賴關係後有地方儲存它,儲存後,我們應該把被依賴的模組注入依賴模組中,注入應該保持被傳遞函式的作用域,被傳遞的函式應該能夠接受自定義引數,而不僅僅是依賴描述。
總結
在JavaScript
中依賴注入的概念不像Java
中被經常提到,主要原因是在js中很容易就實現了這種動態依賴。其實我們大部分人都用過依賴注入,只是我們沒有意識到。即使你不知道這個術語,你可能在你的程式碼裡用到它百萬次了。希望這篇文章能加深你對它的瞭解。
需要注意的是,依賴注入只是控制反轉的一種實現方式,正確的依賴管理是每個開發週期中的關鍵過程。JavaScript 生態提供了不同的工具,作為開發者的我們應該挑選最適合自己的工具。