#前言
##1.CommonJS规范
CommonJS就是为JS的表现来制定规范,因为js没有模块的功能所以CommonJS应运而生,它希望js可以在任何地方运行,不只是浏览器中。
CommonJS能有一定的影响力,我觉得绝对离不开Node的人气,不过喔,Node,CommonJS,浏览器甚至是W3C之间有什么关系呢,我找到了个贴切的图:
|---------------浏览器----- ------------------| |--------------------------CommonJS----------------------------------|
| BOM | | DOM | | ECMAScript | | FS | | TCP | | Stream | | Buffer | |…|
|-------W3C-----------| |---------------------------------------Node--------------------------------------------------|
#CommonJS是一种思想
CommonJS是一种思想,它的终极目标是使应用程序开发者根据>CommonJS API编写的JavaScript应用可以在不同的JavaScript解析器和HOST环境上运行。目前,有四大平台支持CommonJS API:Rhino、Spidermonkey、v8、JavaScriptCore。
如果你写的JavaScript是根据CommonJS API编写的,那么,你就可以在与CommonJS兼容的系统上,用JavaScript做下面这些事情:
编写服务端应用;
编写命令行工具;
编写基于GUI的桌面应用;
#CommonJs规范
1、CommonJs规范的出发点:JS没有模块系统、标准库较少、缺乏包管理工具;为了让JS可以在任何地方运行,以达到Java、C#、PHP这些后台语言具备开发大型应用的能力;
2、在CommonJs规范中:
一个文件就是一个模块,拥有单独的作用域;
普通方式定义的变量、函数、对象都属于该模块内;
通过require来加载模块;
通过exports和modul.exports来暴露模块中的内容;
3、所有代码都运行在模块作用域,不会污染全局作用域;模块可以多次加载,但只会在第一次加载的时候运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果;模块的加载顺序,按照代码的出现顺序是同步加载的;
4、__dirname代表当前模块文件所在的文件夹路径,__filename代表当前模块文件所在的文件夹路径+文件名;
5、require(同步加载)基本功能:读取并执行一个JS文件,然后返回该模块的exports对象,如果没有发现指定模块会报错;
6、模块内的exports:为了方便,node为每个模块提供一个exports变量,其指向module.exports,相当于在模块头部加了这句话:var exports = module.exports,在对外输出时,可以给exports对象添加方法,PS:不能直接赋值(因为这样就切断了exports和module.exports的联系);
7、npm root -g:查看npm全局包安装位置,建议在nvm目录下新建npm\node_modules目录,然后设置npm的全局包安装位置:npm config set prefix “”,然后将该路径添加到环境变量中;
8、npm init -y:初始化一个package.json文件,加上-y就会默认生成该文件,无需一步一步填写;npm docs 包名:查看包的文档;npm install:安装package.json中dependencies属性中所有依赖的包
9、由于npm的服务器是国外的,所以如果你没有和谐工具是下载不了的,这里推荐使用淘宝NPM镜像:http://npm.taobao.org/,与官方NPM的同步频率目前为10分钟一次;安装命令:npm install -g cnpm --registry=https://registry.npm.taobao.org,安装包:cnpm install 包名(其它命令基本一致);
10、如果你不想下载cnpm,npm还提供了一个镜像源管理工具:npm install -g nrm,通过:nrm ls,查看镜像源列表 ,通过:npm use 镜像源,来切换;
11、NPM的模块加载机制:
如果require的是绝对路径文件,查找不会去遍历每个node_modules目录,其速度最快
1).从module.paths数组中(由当前执行文件目录到磁盘根目录)取出第一个目录作为查找基准
2).直接从目录中查找该文件,如果存在则结束查找,如果不存在则进行下一条查找
3).尝试添加.js、.node、.json后缀之后查找,如果存在文件则结束查找,如果不存在则进行下一条查找
4).尝试将require的参数作为一个包来进行查找,读取目录下的package.json文件,取得Main参数指定的文件
5).尝试查找该文件,如果存在则结束查找,如果不存在则进行第3条查找
6).如果继续失败,则取出module.paths数组中的下一目录作为基准查找,循环第1-5个步骤
7).如果继续失败,循环第1-6个步骤,直到module.paths中的最后一个值
8).如果继续失败,则抛出异常
#模块
##require
每个模块中有一个自由变量require,它是一个方法,这个方法接受一个参数,即模块的唯一ID。
require根据外部模块ID,返回该模块输出的API。如果外部模块被required的时候还没有执行完,require至少应改返回该模块的exports(另一个自由变量)。如果必需的模块不存在,require方法应该抛出一个异常。
require可以有一个main属性,属性值要么为undefined,要么等于module(另一个自由变量),这个属性应当是只读的。
require可以有一个paths属性,属性值为由路径字符串组成的数组,路径按优先级从高到低的顺序排列。
##exports
每个模块中还有一个自由变量exports,它是一个对象,模块对外输出的API就绑定在这个对象上。而且exports是模块对外输出API的唯一途径。
// a.js
var sex="boy";
var echo=function(value){
console.log(value)
}
export {sex,echo}
//通过向大括号中添加sex,echo变量并且export输出,就可以将对应变量值以sex、echo变量标识符形式暴露给其他文件而被读取到
//不能写成export sex这样的方式,如果这样就相当于export "boy",外部文件就获取不到该文件的内部变量sex的值,因为没有对外输出变量接口,只是输出的字符串。
// b.js
通过import获取a.js文件的内部变量,{}括号内的变量来自于a.js文件export出的变量标识符。
import {sex,echo} from "./a.js"
console.log(sex) // boy
echo(sex) // boy
##module
每个模块中必须有一个自由变量module,它是对象。这个对象有一个id属性,表示该模块的id,同时应该是只读属性。
module对象可以有一个uri属性,表示这个模块被加载的来源
#模块ID
模块ID是由"“分开的词组成,每个词必须使用驼峰式,或者是”.“或”…"。熟悉路径的同学应该知道".“表示当前路径,”…“表示上一级路径。在这里,”.“表示当前模块,”…"表示上一级模块。
格式举例:A/ModuleID。
模块ID中可以出现".js"文件后缀
#2.AMD
CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,为什么这么说呢?
这需要分析一下浏览器端的js和服务器端js都主要做了哪些事,有什么不同了:
---------------------------------------服务器端JS | 浏览器端JS-------------------------------------------
相同的代码需要多次执行 | 代码需要从一个服务器端分发到多个客户端执行
CPU和内存资源是瓶颈 | 带宽是瓶颈
加载时从磁盘中加载 | 加载时需要通过网络加载
于是乎,AMD(异步模块定义)出现了,它就主要为前端JS的表现制定规范。
AMD就只有一个接口:define(id?,dependencies?,factory);
它要在声明模块的时候制定所有的依赖(dep),并且还要当做形参传到factory中,像这样:
1 define(['dep1','dep2'],function(dep1,dep2){...});
要是没什么依赖,就定义简单的模块,下面这样就可以啦:
1 define(function(){
2 var exports = {};
3 exports.method = function(){...};
4 return exports;
5 });
咦,这里有define,把东西包装起来啦,那Node实现中怎么没看到有define关键字呢,它也要把东西包装起来呀,其实吧,只是Node隐式包装了而已…
RequireJS就是实现了AMD规范的呢。
这有AMD的WIKI中文版,讲了很多蛮详细的东西,用到的时候可以查看:AMD的WIKI中文版
#3.CMD
大名远扬的玉伯写了seajs,就是遵循他提出的CMD规范,与AMD蛮相近的,不过用起来感觉更加方便些,最重要的是中文版,应有尽有:seajs官方doc
1 define(function(require,exports,module){...});
用过seajs吧,这个不陌生吧,对吧。