寫在最前
本次分享一下我學習到的有關依賴注入的梳理與總結。試圖生動形象得解釋出來其內部的思想與實現流程。
歡迎關注我的博客,不定期更新中——
什麼是依賴注入
第一次聽到這個說法是在angular的時候,我們都知道angular內部大量使用了依賴注入。雖然我到現在也沒玩過:),不過這並不影響我們來探究一下它。
首先試圖形象的說明一下(個人觀點、有問題歡迎指正):有那麼一羣人,這羣人的職業是程序員。他們除了工作不想費力氣去做別的事。除了上班剩下的只有買吃的和買格子衫。具體吃什麼和格子衫什麼樣子他們並不關心。那麼也許我們可以提供一個公共服務,來專門爲程序員提供吃的和格子衫。程序員不需要關心我們怎麼做吃的和去哪裏買格子衫,他們只需要告訴我們他們需要就可以了,買好之後我們自然會給他們送到。這樣就可以避免每個程序員還要花費心思獨自的去吃東西和買格子衫,省去了大把時間就可以更好的投入到工作中了。
剛剛那段說法可以抽象爲下面這張簡易示意圖:
按照上面圖的流程中我們可以知道我們需要實現這麼幾件事:
- 提供一個服務容器
- 爲目標函數註冊需要的依賴
- 獲取目標函數註冊的依賴項
- 通過依賴項來查詢對應服務
- 將獲取的依賴項傳入目標函數
提供一個服務容器
//假裝提供一些服務
var services = {
A: () => {console.log(1)},
B: () => {console.log(2)},
C: () => {console.log(3)}
}
爲目標函數註冊需要的依賴
// 目標函數
function Service(A, B) {
A()
B()
}
目前的註冊方式採用在形參的方式來傳遞,我們不需要關心A、B是怎麼實現的,我們只需要知道這些代表着吃的和格子衫就可以了:)
獲取目標函數註冊的依賴項
// 獲取func的參數列表(依賴列表)
getFuncParams = function (func) {
var matches = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m);
if (matches && matches.length > 1)
return matches[1].replace(/\s+/, '').split(',');
return [];
}
實現原理爲將傳入的目標函數進行正則匹配,匹配出形參。這其中的關鍵點在於這段正則表達式:
/^function\s*[^\(]*\(\s*([^\)]*)\)/m
其中\(\s*([^\)]*
通過括號來提取匹配到function後面參數括號的內部內容,也就是可以得到參數字符串。這裏面是運用了括號的提取數據的規則來獲取的信息,規則如下:
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
console.log( string.match(regex) );
// => ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"]
結果數組中第一個元素爲匹配結果,之後爲括號內的數據,由此我們便可知道,這段正則通過括號的使用,獲取到了整個形參作爲一個字符串,之後再通過split進行拆分就得到了我們想要的結果。
通過依賴項來查詢對應服務
//簡易實現
setFuncParams = function (params) {
for (var i in params) {
params[i] = services[params[i]];
}
return params;
}; //依次對應服務中的項進行查找返回結果。
將獲取的依賴項傳入目標函數
// 注射器
function Activitor(func, scope) {
return () => {
func.apply(scope || {}, setFuncParams(getFuncParams(func)));
}
}
// 實例化Service並調用方法
var service = Activitor(Service);
service();//1 2
小結
至此我們便完整地實現了一個很簡單的依賴注入的模式,源碼在這裏。非常簡單,同時也沒有做很多的判斷。不過核心的思路還是梳理了出來。自己悶頭琢磨了半天,有不對的地方歡迎斧正~ PS:下面的幾篇參考資料寫的都很好,其中顏海鏡老師的JavaScript裏的依賴注入很有深意,拜讀了很久,也分享給大家。
參考資料
最後
慣例po作者的博客,不定時更新中——
有問題歡迎在issues下交流。