当我使用 angular.module(...).controller(...).directive(...) 时会发生什么?为什么?

What happens when I use angular.module(...).controller(...).directive(...)?And why?

我认为这等于

var module = angular.module(...);
module.controller(...);
module.directive(...);

但我不确定。而且我不知道 angular 中发生了什么,也不知道为什么我可以这样写代码。

我尝试调试和跟踪它,但它很混乱。

What happens when I use angular.module(…).controller(…).directive(…)?And why?

简答

这是在一个文件中编写代码的好方法。

如果要将 Angular 项目拆分为不同的文件,请使用第二种方法:

var app = angular.module(...);
app.controller(...);
app.directive(...);

长答案

另请查看此 angular 代码片段(摘自 https://code.angularjs.org/1.5.6/angular.js):

可以看到controllerdirectivemodulefilterfactoryvalueproviderdecorator, animation, config, component,run returns moduleInstance

function setupModuleLoader(window) {

  var $injectorMinErr = minErr('$injector');
  var ngMinErr = minErr('ng');

  function ensure(obj, name, factory) {
    return obj[name] || (obj[name] = factory());
  }

  var angular = ensure(window, 'angular', Object);

  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
  angular.$$minErr = angular.$$minErr || minErr;

  return ensure(angular, 'module', function() {
    /** @type {Object.<string, angular.Module>} */
    var modules = {};


    return function module(name, requires, configFn) {
      var assertNotHasOwnProperty = function(name, context) {
        if (name === 'hasOwnProperty') {
          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
        }
      };

      assertNotHasOwnProperty(name, 'module');
      if (requires && modules.hasOwnProperty(name)) {
        modules[name] = null;
      }
      return ensure(modules, name, function() {
        if (!requires) {
          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
             "the module name or forgot to load it. If registering a module ensure that you " +
             "specify the dependencies as the second argument.", name);
        }

        /** @type {!Array.<Array.<*>>} */
        var invokeQueue = [];

        /** @type {!Array.<Function>} */
        var configBlocks = [];

        /** @type {!Array.<Function>} */
        var runBlocks = [];

        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);

        /** @type {angular.Module} */
        var moduleInstance = {
          // Private state
          _invokeQueue: invokeQueue,
          _configBlocks: configBlocks,
          _runBlocks: runBlocks,


          requires: requires,

          name: name,

          provider: invokeLaterAndSetModuleName('$provide', 'provider'),


          factory: invokeLaterAndSetModuleName('$provide', 'factory'),

          service: invokeLaterAndSetModuleName('$provide', 'service'),

          value: invokeLater('$provide', 'value'),

          constant: invokeLater('$provide', 'constant', 'unshift'),

          decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),

          animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),

          filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),

          controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),

          directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),

          component: invokeLaterAndSetModuleName('$compileProvider', 'component'),

          config: config,

          run: function(block) {
            runBlocks.push(block);
            return this;
          }
        };

        if (configFn) {
          config(configFn);
        }

        return moduleInstance;

        function invokeLater(provider, method, insertMethod, queue) {
          if (!queue) queue = invokeQueue;
          return function() {
            queue[insertMethod || 'push']([provider, method, arguments]);
            return moduleInstance;
          };
        }

        function invokeLaterAndSetModuleName(provider, method) {
          return function(recipeName, factoryFunction) {
            if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
            invokeQueue.push([provider, method, arguments]);
            return moduleInstance;
          };
        }
      });
    };
  });
}

Why is it better?

两种方法的作用相同,因此开发人员将决定哪种方法更适合他的项目结构

for efficiency?

没有效率值测量,两者具有相同的效率。没有性能损失。

for what?

在项目中我想在​​单独的文件中编写每个指令每个控制器...所以我使用 app.controller(...);, app.service(...); ,...

但是 common 指令我想放在一个文件中所以我使用:

app.directive(…).directive(…).directive(…).directive(…).directive(…)

希望它能对您的理解有所启发 :)

这才叫一口流利API。

每个方法都会return模块实例,以便可以调用另一个方法。

为了说明,我们可以创建一个执行类似操作的 class。

class Module {

  controller() {
    console.log('controller');
    return this;
  }

  directive() {
    console.log('directive');
    return this;
  } 
}

每个方法完成后,它将 return 模块实例 this 以便可以链接另一个方法。

所以现在我们可以使用这个 class 并像这样链接方法:

new Module().controller().directive();

const module = new Module();
module.controller();
module.directive();