[js模块规范]总结JS模块规范CommonJS,AMD,CMD区别

#前言
##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吧,这个不陌生吧,对吧。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图解AI

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值