controller - acelan86/angular GitHub Wiki

从一段常见的代码入手: html:

<html ng-app>
  <head>
    <script src="angular.js"></script>
    <script src="controllers.js"></script> 
  </head>
  <body>
    <div ng-controller='HelloController'>
      <p>{{greeting.text}}, World</p>
    </div>
  </body>
</html>

controller.js

function HelloController($scope) {
  $scope.greeting = { text: 'Hello' };
}

anguler启动后,会调用helloController作为初始controller,那么它是怎么做的:

//$ControllerProvider
function $ControllerProvider() {
  var controllers = {}; //存储当前注册的controller
  
  /* 
   * 注册controller,这个方法在通过module.controller('name', function () {})声明一个controller的时候调用
   * 将controller写入controllers对象中
   */
  this.register = function(name, constructor) {
    if (isObject(name)) {
      extend(controllers, name)
    } else {
      controllers[name] = constructor;
    }
  };

  /*
   * provider的$get方法,用来获取它提供的实际controller
   */
  this.$get = ['$injector', '$window', function($injector, $window) {
    //重点在这里
    return function(constructor, locals) {
      if(isString(constructor)) {
        var name = constructor;
        //先从controllers里面找是否有注册name的controller 
        constructor = controllers.hasOwnProperty(name)
            ? controllers[name]  //有,直接返回
            : getter(locals.$scope, name, true) || getter($window, name, true); //没有,从locals.$scope中找,没有,再从window中找

        assertArgFn(constructor, name, true); //mock用
      }

      return $injector.instantiate(constructor, locals); //这里简单看作调用injector.invoke进行依赖注入并调用controller的定义方法。
    };
  }];

从这里可以看出,上面的例子在读到ng-controller指令的时候,会从controllerProvider中要求获取实际controller,也就是使用$get方法,因为没有使用module.controller进行注册,所以这里应该是从window上取到实际的controller。 下面的例子展示了从controllers中获取的情况:

angular.module('mymodule', [])
  .controller('myctrl', function () { ... });
⚠️ **GitHub.com Fallback** ⚠️