Angular的注射器如何获得它的全知?

时间:2013-12-04 04:38:54

标签: angularjs angularjs-directive

以下示例取自angularJS docs http://docs.angularjs.org/guide/directive

在这个例子中,注入器按名称知道 $ timeout ,按名称知道 dateFilter ,即使javascript没有命名参数(如Python)。所以我添加了一个调试器语句,看看它如何设法将这个魔法拉下来,然后向前走10帧堆栈帧,我得出结论我完全迷失了!

我在角落里看到了这个地方,这个神奇的注射器以某种方式设法将正确的部分组合在一起进行函数调用。我只是不明白他们是怎么做到的。我的指令可以很容易地将$ location或其他东西作为函数的第一个参数,它将获得正确的对象以便它可以工作。魔术如何运作????

<!doctype html>
<html ng-app="docsTimeDirective">
<head>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.js"></script>
  <script type="text/javascript">
  debugger;
  angular.module('docsTimeDirective', [])
    .controller('Ctrl2', function($scope) {
      $scope.format = 'M/d/yy h:mm:ss a';
    })
    .directive('myCurrentTime', function($timeout, dateFilter) {
      debugger;

      ...

  </script>
</head>
<body>
  <div ng-controller="Ctrl2">
    Date format: <input ng-model="format"> <hr/>
    Current time is: <span my-current-time="format"></span>
  </div>
</body>
</html>

1 个答案:

答案 0 :(得分:1)

这一切都发生在下面的一段代码中,它基本上使用toString()作为工厂传递给angular的函数,并使用正则表达式从函数的字符串表示中提取参数名称:

var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
function annotate(fn) {
  var $inject,
      fnText,
      argDecl,
      last;

  if (typeof fn == 'function') {
    if (!($inject = fn.$inject)) {
      $inject = [];
      if (fn.length) {
        fnText = fn.toString().replace(STRIP_COMMENTS, '');
        argDecl = fnText.match(FN_ARGS);
        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
          arg.replace(FN_ARG, function(all, underscore, name){
            $inject.push(name);
          });
        });
      }
      fn.$inject = $inject;
    }
  } else if (isArray(fn)) {
    last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
  } else {
    assertArgFn(fn, 'fn', true);
  }
  return $inject;
}