AngularJS中的依賴注入實際應用場景有哪些?
所謂依賴注入,通俗地舉例,有個人養了一只寵物,他可以喂寵物吃東西,寵物會自己吃:
function PetKeeper(pet) {
this.pet = pet;
}
PetKeeper.prototype.feed = function(food) {
this.pet.eat(food);
};
function Pet(type) {
this.type = type;
}
Pet.prototype.eat = function(food) {
alert("I am a " + this.type + ", I'm eating " + food);
};
var tom = new Pet("cat");
var jerry = new Pet("mouse");
var keeper = new PetKeeper(tom);
keeper.feed("fish");
keeper.pet = jerry;
keeper.feed("rice");
這個例子里,pet是外部注入的,在feed函數定義里,并不知道pet到底是什么(在帶接口的語言里,至少還是知道是個什么,在動態語言里就是兩眼一抹黑了……),只有當它被調用的時候,才知道pet是什么。
這個過程的好處是什么呢?如果我們在PetKeeper內部去創建tom或jerry,就表示PetKeeper要對Pet產生依賴。一個對別人有依賴的東西,它想要單獨測試,就需要在依賴項齊備的情況下進行。如果我們在運行時注入,就可以減少這種依賴,比如在單元測試的時候使用模擬類就行。
比如你有一個a,依賴于b,實際業務中,b的實現很復雜:
function A(b) {
this.b = b;
}
A.prototype.a1 = function() {
alert(100 + this.b.b1());
};
function B() {}
B.prototype.b1 = function() {
//這里可能很復雜而且不好模擬,比如依賴于生產環境的一些調用
}
那么,我如何用單元測試來驗證A自身的邏輯是正確的呢?如果有強依賴,這里就不好辦了,必須實例化真正的B,但是B的調用要依賴于生產環境。換個方式考慮,我們用一個接口與B相同的類來做模擬,只要改變它的返回值,實現各種邊界條件,把它的實例注入到A的構造函數中,就可以讓A自身的邏輯得到測試了。
function MockB() {}
MockB.prototype.b1 = function() {
return 99;
};
在AngularJS里,依賴注入的目的是為了減少組件間的耦合,它的實現是這個過程:
function Art(Bar, Car) {}
我怎么知道這個Art在實例化的時候要傳入Bar和Car的實例呢?形參名稱是沒法取到的,所以只有狠一點,用toString()來取到剛才這一行字符串,然后用正則表達式取到Bar和Car這兩個字符串,然后到模塊映射中取到對應的模塊,實例化之后傳入。
但是這樣也有問題,如果這個js被壓縮了,很可能命名都變了,壓縮成了這樣:
function a1(b1, b2) {}
這時候再這樣就不知道原先是什么類型了。在這里,有類型聲明的語言就不會有問題,比如:
function art(bar:Bar, car:Car) : Art {}
就算你把art, bar, car都改名了,也還是能知道類型,但js里不行。所以,怎么辦呢?
aaa.controller("Art", [function(Bar, Car) {}, "Bar", "Car"]);
注意在AngularJS里面,他很可能建議你這么寫,但也可以這么寫:
Art.$inject = ["Bar", "Car"];
這么一來,我只要拿到Art,就能取到依賴項的名稱了,就可以實例化再注入,也不怕壓縮了。