本节书摘来自华章出版社《AngularJS深度剖析与最佳实践》一书中的第2章,第2.2节,作者 雪狼 破狼 彭洪伟,更多章节内容可以访问云栖社区“华章计算机”公众号查看
2.2 模块
与其他现代语言不同,当前版本的JavaScript(ECMAScript 5)并没有内置模块化语法。但是,随着程序规模越来越大,模块化的需求越来越重要,于是出现了require.js等第三方库,试图用库来弥补语言的不足。Angular并不依赖require.js等第三方库,而是自己实现了模块化系统,这个系统的核心就是模块(module)。
我们先来回顾一下“模块”的概念,然后自然就明白Angular中的module是怎么回事了。
所谓模块是指把相关的一组编程元素(如类、函数、变量等)组织到同一个发布包中。这些编程元素之间紧密协作,隐藏实现细节,只通过公开的接口与其他模块合作。
模块是一个粒度适中的复用单位,也是最常见的复用形式。比如我们常用的第三方库往往对外公开好几个类,使用者只要关注其公开接口就可以了,不用了解其实现细节,这种第三方库就是一个“模块”。
Angular的module也是如此。Angular中的编程元素包括Service、Directive、Filter、Controller等,它们只有通过模块进行“导出”才能供别人使用。如:angular.module('com.ngnice.app').service('ui', function() {...});语句的作用是:先取出一个名为com.ngnice.app的模块,然后把function() {...}作为一个回调函数以ui作为名字注册进去。这样,别人就可以随时通过ui这个名字把它从com.ngnice.app模块中取出来。
所以,我们可以简单地把模块看做一个注册表(registry),它保存着名字和编程元素的对照表,既可以存入,也可以取出。
一个程序往往不会只含有一个模块,这些模块需要互相协作,这就导致了模块之间具有依赖关系,比如有一个可复用模块,名叫common,而我们的应用想要使用其中名叫authHandler的service。那么我们就要先声明这种依赖关系:angular.module('com.ngnice.app', ['common']),这样,Angular就知道该去common模块中查找这个名叫authHandler的Service。如果没有声明这种依赖关系,那么就算引入了它所在的JavaScript文件,也照样是无法找到的,这是新手很容易踩坑的地方,请特别注意。同时,Angular还可以自动检测出循环依赖,以免出现无限递归。
注意,我们刚才调用了两次module函数:angular.module('com.ngnice.app')和angular.module('com.ngnice.app', ['common']),前者可不是后者的简写形式,而是具有完全不同的含义:前者的作用是引用一个模块,也就是说查找一个名叫app的模块,并返回其引用,如果模块不存在,则会触发一个异常[$injector:nomod] Module 'com.ngnice.app' is not available...;而后者的作用是创建一个模块,并且声明这个模块需要依赖一个名为common的模块,第二个参数是个数组,所以还可以声明依赖更多个模块。
模块依赖关系是一棵树,这就意味着:凡是依赖了app模块的更高级模块,也会自动依赖app所依赖的common等模块。