隨着前端承擔的職責愈來愈重,前端應用向着複雜化、規模化的方向發展。大型項目模塊化是一種趨勢,不可避免模塊之間要相互依賴,此外還有不少第三方包。這樣的話如何去管理這些繁雜的文件,是一個不可避免的話題。此時做爲一種已經被實踐證實過的思想模式一直獲得你們的青睞,這就是控制反轉(IOC)。前端
先看一下維基百科上的定義:
控制反轉(Inversion of Control,縮寫爲IoC),是面向對象編程中的一種設計原則,能夠用來減低計算機代碼之間的耦合度。其中最多見的方式叫作依賴注入(Dependency Injection,簡稱DI),還有一種方式叫「依賴查找」(Dependency Lookup)。經過控制反轉,對象在被建立的時候,由一個調控系統內全部對象的外界實體,將其所依賴的對象的引用傳遞給它。也能夠說,依賴被注入到對象中。git
針對前端來講,接口的概念不那麼清晰明瞭,不像強類型語言。 概念是比較枯燥的,下面結合例子來看一下可能更好理解一點。github
根據概念能夠看到最主要的目的就是下降耦合,提升擴展性。在深究以前,咱們先看下代碼耦合編程
所謂耦合,能夠以下圖顯示: 比較清晰明瞭,代碼相互之間的聯繫太直接: 假如obj2報錯,那麼整個系統也都報錯了。
因此咱們的目的就是下降兩者之間的耦合度,
結合圖來講比較清晰,
若是二者不這麼直接的發生關係,那麼相互影響的機率就小了那麼多了。設計模式
另外,這是比較少的模塊,常規項目裏顯然不只僅是隻有這麼少,想象一下多個模塊的場景: 這裏除了耦合以外,不一樣齒輪之間的依賴關係也是個頭疼的問題,迭代個幾個版本以後發現,這是什麼東西,一動就有bug。。。。模塊化
因此IOC就是來解決上述問題的。 其常見方式是依賴注入和依賴查找。在js領域裏面最出名的就是angular中大量使用了依賴注入。文字比較蒼白,咱們能夠經過例子來看看。函數
就從nba來講,有那麼一些球星,咱們想知道他所屬的球隊,那麼可能就像下面這個狀況:post
//球隊信息
class RTeam {
constructor(){
this.name = '火箭'
}
}
// 球員信息
class Player{
constructor(){
this.team = new Team()
}
info(){
console.log(this.team.name)
}
}
// 球員ym
let ym = new Player()
ym.info() // ‘火箭’
複製代碼
看起來挺好的,球員player依賴於某個球隊RTeam 當調用的時候主動去加載球隊便可。此時的控制權在player這裏。學習
假如這個時候,球員發生交易了,球隊信息更換了,轉換到team2了。
這時候咱們就須要去修改player裏的代碼了,由於球員那裏直接寫死了對RTeam的依賴,這種可擴展性是不好的。 這不是咱們所想要的,須要從新思考下依賴關係處理了。
球員和球隊之間非得這麼直接粗暴的發生聯繫嗎,
一個球員對應一個球隊的話,將來會發生變化的可能性太大了,畢竟不止一個球隊。
若是二者之間不直接發生聯繫,中間就須要一箇中間模塊來負責二者關係的處理
球員不關注球隊從哪來,只要給到我就好了。
這樣控制權就不是直接落在player這裏了,這正是IOC的設計思路。ui
參照IOC的幾條原則,咱們進行下改進。
高層模塊不該該依賴低層模塊。兩個都應該依賴抽象 這裏player是高層模塊,直接依賴了球隊這個低級模塊。因此咱們將二者解耦,player再也不直接依賴於該team這個class
抽象不該該依賴具體實現,具體實現應該依賴抽象
具體到這裏來看咱們的player模塊不該該直接依賴具體team,而是經過構造函數將抽象的teaminfo實例傳遞進去,這樣就解耦具體實現。
直接看代碼比較清楚:
// 球隊信息不依賴具體實現
// 面向接口即面向抽象編程
class TeamInfo {
constructor(name) {
this.name = name
}
}
class Player {
// 此處的參數,是teamInfo的一個實例,不直接依賴具體的實例
// 面向抽象
constructor(team) {
this.team = team
}
info() {
console.log(this.team.name)
}
}
// 將依賴關係放到此處來管理,控制權也放到此處
// Player和TeamInfo之間再也不有直接依賴
// 本來直接掌握teaminfo控制權的player再也不直接依賴
// 將依賴控制,落在此處(第三方模塊專門管理)即爲控制反轉
var ym = new Player(new TeamInfo('火箭'))
ym.info()
var kobe = new Player(new TeamInfo('湖人'))
kobe.info()
複製代碼
這裏發現,TeamInfo和Player之間已經沒有直接關聯了,依賴關係統一放到getTeamInfo中。
所謂控制反轉就如何上面同樣,將依賴的控制權由player轉移到其餘地方即咱們專門的依賴管理來作了。 這樣再增長一個team3,改動也不大,複用就好了。 其中之間的關係,以下面這個圖: 彼此不直接發生聯繫,依賴關係統一在中間模塊來管理,更加清晰。
上面其實就是最簡單的IOC實現了,基於IOC的編程思想,主要有兩種實現方式:依賴注入和依賴查找。依賴查不太經常使用,常見的是依賴注入。
在js中常見的就是依賴注入。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象的來講,即由容器動態的將某種依賴關係注入到組件之中。
在RequireJS/AMD的模塊加載器的實現就是基於依賴注入來的,還有大名鼎鼎的angular,其實現也使用了大量的依賴注入。
關於控制反轉,一句話總結:控制反轉這裏控制權從使用者自己轉移到第三方容器上,而非是轉移到被調用者上,這裏須要明確不要疑惑。控制反轉是一種思想,依賴注入是一種設計模式。 可能聽起來比較抽象,其實咱們平時開發中見到和用到的也是蠻多的,可能原來沒有對應起來罷了。 至於依賴注入,前端領域用到的就更多了,下面我將結合自身實踐翻譯一篇我的認爲很好的文章Dependency-injection-in-JavaScript,來進一步深刻依賴注入。 至此,我的看法分享完畢,拋磚引玉,但願共同窗習進步。更多文章請移步個人博客