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

Passing a function as parameter - array notation

本文关键字:数组 表示 参数 传递函数      更新时间:2023-09-26

将函数传递给各种AngularJS方法的推荐方法是使用AngularJS文档中称为数组表示法的语法。

你应该这样做:

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

而不是:

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

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

我想知道传递函数作为参数的第一种方式是JavaScript标准中提到的语法吗?我还没有设法找到任何关于"数组符号"在这种情况下在网络上。

这只是一个约定——但考虑得很周到,因此在Angular中一直在使用。你看,一个函数——一个模块——可以只有一个依赖项(就像你的例子中那样),也可以有很多依赖项(从两个开始),或者根本没有依赖项。所以我们需要一些解决方案来解决所有的情况。

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

这些缺点已经够糟糕的了,所以必须有另一种方法。但是,我们不想去掉参数列表(这些深度仍然必须以某种方式在函数中处理,对吧?)但现在很明显,单一的列表是不够的——它必须在某个地方复制。

这就是Array(元素的有序序列)非常方便的地方。现在注入器只需要分离该数组的最后一个元素就可以得到完整的深度列表。那些是字符串,不是变量,所以它们不会被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分支是用于旧的方式-深度表示为函数参数。第二个(更容易阅读和执行)-用于放置在数组中的深度和函数(函数是最后一个元素)。

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

对于AngularJS来说,符号本身并没有什么神奇之处。函数可以是数组成员,就像其他数据类型一样。