传递函数作为参数 - 数组表示法

时间:2015-09-06 14:55:44

标签: javascript angularjs

将函数传递给各种AngularJS方法的推荐方法是使用在AngularJS docs中调用的语法数组符号。

你应该这样做:

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

而不是:

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

因为AngularJS依赖注入和缩小的工作方式。

我想知道将函数作为参数传递的第一种方法是否是JavaScript标准中提到的语法?我没有在网络上找到关于'数组符号'的任何内容。

2 个答案:

答案 0 :(得分:1)

它只是一个带字符串和函数的数组。

关于符号本身没有什么神奇的或AngularJS。函数可以像任何其他数据类型一样是数组成员。

答案 1 :(得分:1)

这只是一个惯例 - 但它的思考得很好,因此在整个Angular中使用过。看一个函数 - 一个模块 - 只能有一个依赖(如你的例子),或者其中很多(从两个开始,右边),或者根本没有依赖。所以我们需要一些解决所有案例的解决方案。

天真的方法是将所有deps指定为函数参数(第二个示例)。现在,可以通过分析函数源代码来提取(并注入)它们。 Pro:写入的绝对最小代码(无论如何,您必须指定所有deps'名称)。缺点:1)基于反射(永远不会很快),2)在脚本缩小时中断(并且所有参数名称都被转换)。

这些缺点很糟糕,所以必须采用另一种方式。我们不想摆脱参数列表(那些deps仍然必须以某种方式在函数内解决,对吧?)。但现在很清楚,单个列表还不够 - 它必须在某个地方复制。

这就是Array - 一个有序序列的元素 - 非常方便。现在,注入器只需要分离该数组的最后一个元素以获取完整的deps列表。这些是字符串,而不是变量,所以它们不会被minifier修改。什么甚至更好,现在我们不必分析签名,因此注射器的工作速度更快。

从理论到实践:这就是在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分支用于旧方式 - 表示为函数参数的deps。第二个(更容易阅读和执行) - 对于放置在数组中的deps和函数(函数是最后一个元素)。