這只是一個約定 - 但它的思想很好,因此在Angular中使用。看,一個函數 - 一個模塊 - 可以只有一個依賴項(如你的例子),或者它們中的許多(從兩個開始),或者根本不依賴。所以我們需要一些解決方案來回答所有的情況。
幼稚的方法是指定所有的deps作爲函數參數(第二個例子)。現在,可以通過分析函數源代碼來提取(並注入)它們。 Pro:絕對編寫的最小代碼(無論如何您都必須指定所有代碼的名稱)。缺點:1)基於反射(從不快),2)當腳本被縮小時(所有參數的名稱都被轉換)中斷。
這些缺點足夠糟糕,所以只能有另一種方式。我們不希望擺脫參數列表,但(這些代價仍然必須在函數內以某種方式解決,對嗎?)。但是現在很清楚,單個列表是不夠的 - 它必須在某個地方複製。
而這就是Array - 一個命令序列的元素 - 非常方便。現在注入器只需分離該數組的最後一個元素即可獲得完整的縮放列表。那些是字符串,而不是變量,所以它們不會被縮小器修改。更好的是,現在我們不必分析簽名,因此噴油器工作速度更快。
從理論到實踐:這是這兩種方法是如何在Angular 1.x DI模塊來實現:
function annotate(fn, strictDi, name) {
var $inject,
fnText,
argDecl,
last;
if (typeof fn === 'function') {
// first approach: only function is passed, we need to analyze the args list
if (!($inject = fn.$inject)) {
$inject = [];
if (fn.length) {
if (strictDi) {
if (!isString(name) || !name) {
name = fn.name || anonFn(fn);
}
throw $injectorMinErr('strictdi',
'{0} is not using explicit annotation and cannot be invoked in strict mode', name);
}
// get rid of comments, it's possible to have those inside `()`
fnText = fn.toString().replace(STRIP_COMMENTS, '');
// extract arguments
argDecl = fnText.match(FN_ARGS);
// push those into injector
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
arg.replace(FN_ARG, function(all, underscore, name) {
$inject.push(name);
});
});
// ... and that took some time
}
fn.$inject = $inject;
}
} else if (isArray(fn)) {
// second approach: an array is passed
last = fn.length - 1;
// make sure its last element is a function
assertArgFn(fn[last], 'fn');
// use all but the last element as list of deps
$inject = fn.slice(0, last);
// ... and that's all, believe it or not!
} else {
assertArgFn(fn, 'fn', true);
}
return $inject;
}
正如你看到的,第一if
分支是舊的方式 - 的DEP表示爲函數參數。第二個(更容易閱讀和執行) - 放置在數組中的函數(功能是最後一個元素)。
在JS中沒有提到它,因爲它只是一個約定 - 但是很容易遵循。在相應的代碼中,檢查參數的類型就足夠了:如果它只是一個函數,則嘗試通過分析其源代碼來提取依賴關係。 – raina77ow
不,您可以在函數和角度處理它們之前傳遞一堆字符串。 – kappaallday