2015-09-06 40 views
0

將函數傳遞給各種AngularJS方法的推薦方法是使用在AngularJS文檔中調用的語法,數組表示法。傳遞函數作爲參數 - 數組表示法

你應該這樣做:

app.controller("MyCtrl", ['$scope', function($scope){ 
$scope.someData = "Array notation"; 
}]); 

,而不是這樣的:

app.controller("MyCtrl", function($scope){ 
$scope.someData = "non-array notation"; 
}); 

因爲這樣AngularJS依賴注入和微小的作品。

我想知道作爲參數傳遞函數的第一種方式是JavaScript標準中提到的語法嗎?我還沒有設法在網絡上找到關於「數組符號」的任何內容。

+0

在JS中沒有提到它,因爲它只是一個約定 - 但是很容易遵循。在相應的代碼中,檢查參數的類型就足夠了:如果它只是一個函數,則嘗試通過分析其源代碼來提取依賴關係。 – raina77ow

+0

不,您可以在函數和角度處理它們之前傳遞一堆字符串。 – kappaallday

回答

1

這只是一個約定 - 但它的思想很好,因此在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表示爲函數參數。第二個(更容易閱讀和執行) - 放置在數組中的函數(功能是最後一個元素)。

+0

感謝您的驚人答案!我很好奇 - 在assertArgFn(fn [last],'fn')中可能有'fn'的用途?方法名稱本身assertArg ** Fn **毫無疑問地關於它應該做什麼。 – user107986

+0

你是對的,但它適用於不同的參數。查看[源代碼](https://github.com/angular/angular.js/blob/f13852c179ffd9ec18b7a94df27dec39eb5f19fc/src/Angular.js#L1731)瞭解詳情;你會發現在這個特殊情況下'fn'只是參數的名字。 – raina77ow

+0

我的觀點是,這個功能採用了「名稱」這個參數,並且在它的身體中並沒有做任何事情。那麼採取這個論點有什麼意義呢?我必須在這裏錯過一些東西。 – user107986

1

它只是一個帶有字符串和函數的數組。

關於符號本身沒有什麼不可思議的或AngularJS。函數可以像任何其他數據類型一樣成爲數組成員。