Search code examples
javascriptangularjslanguage-implementation

How does Angular know what to inject if I don't specify strings?


Consider this code:

angular.module('app', [])
  .controller('MainCtrl', function ($scope) {
    ...
  });

I know that to avoid problems with injection when the JS is minified, the array form of Dependency Injection should be used:

angular.module('app', [])
  .controller('MainCtrl', ['$scope', function ($scope) {
    ...
  }]);

But how does Angular know in the first case (non-array) what to inject? What if I use .controller('MainCtrl', function (scop) instead of $scope? Does it parse my JS and look for function parameter names that match some of its providers?


Solution

  • Notice that the controller's function is a parameter of the function controller. That allows Angular to get that function in a variable and analyze its parameters, and with that angular makes a list of the services that need to be injected.

    In the code bellow you can see what Angular does behind the scenes in order to match those parameters:

    var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
    var FN_ARG_SPLIT = /,/;
    var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
    var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
    
    function annotate (fn) {
      var $inject = [];
      fn = fn.toString();
      var first = fn.replace(STRIP_COMMENTS, '');
      var second = first.match(FN_ARGS)[1];
      var third = second.split(FN_ARG_SPLIT);
      third.forEach(function (arg) {
        arg.replace(FN_ARG, function (all, underscore, name) {
          $inject.push(name);
        });
      });
      return $inject;
    }