在angular中文社区群中,有时会听见某些同学问关于”ng:areq“的错误:
[ng:areq] Argument 'DemoCtrl' is not a function,got undefined!
这往往是因为忘记定义controller或者是声明了多次module,多次声明module会导致前边的module定义信息被清空,所以程序就会找不到已定义的组件。这我们也能从angular源码中了解到(来自loader.js):
function setupModuleLoader(window) { ... function ensure(obj,name,factory) { return obj[name] || (obj[name] = factory()); } var angular = ensure(window,'angular',Object); return ensure(angular,'module',function() { 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,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); } var invokeQueue = []; var runBlocks = []; var config = invokeLater('$injector','invoke'); var moduleInstance = { _invokeQueue: invokeQueue,_runBlocks: runBlocks,requires: requires,name: name,provider: invokeLater('$provide','provider'),factory: invokeLater('$provide','factory'),service: invokeLater('$provide','service'),value: invokeLater('$provide','value'),constant: invokeLater('$provide','constant','unshift'),animation: invokeLater('$animateProvider','register'),filter: invokeLater('$filterProvider',controller: invokeLater('$controllerProvider',directive: invokeLater('$compileProvider','directive'),config: config,run: function(block) { runBlocks.push(block); return this; } }; if (configFn) { config(configFn); } return moduleInstance; function invokeLater(provider,method,insertMethod) { return function() { invokeQueue[insertMethod || 'push']([provider,arguments]); return moduleInstance; }; } }); }; }); }
在代码中,我们能了解到angular在启动时,会设置全局的angular对象,然后在angular对象上发布module这个API。关于module API代码,能清晰的看见第一行谓语句,module名称不能以hasOwnProperty命名,否则会抛出”badname“的错误信息。紧接着,如果传入了name参数,其表示是声明module,则会删除已有的module信息,将其置为null。
从moduleInstance的定义,我们能够看出,angular.module为我们公开的API有:invokeQueue、runBlocks、requires、name、provider、factory、servic、value、constant、animation、filter、controller、directive、config、run。其中invokeQueue和runBlocks是按名约定的私有属性,请不要随意使用,其他API都是我们常用的angular组件定义方法,从invokeLater代码中能看到这类angular组件定义的返回依然是moduleInstance实例,这就形成了流畅API,推荐使用链式定义这些组件,而不是声明一个全局的module变量。
最后,如果传入了第三个参数configFn,则会将它配置到config信息中,当angular进入config阶段时,它们将会依次执行,进行对angular应用或者angular组件如service等的实例化前的配置。