• JS模块化的基本原理
  • commonjs规范
  • commonjs在前端模块化中的基本使用
  • AMD与CMD规范剖析博客链接

一、JS模块化基本原理

在JS没有提出来模块化的时候,开发JS项目比较简单,同时也比较杂乱,第一个问题就是全局变量的管理,为了解决这个问题基本上都使用了命名空间和闭包两个主流的解决方式,但是随着硬件基础和网络环境的改善,前端开发也越来越复杂,需要协同合作,代码复用的需求越来越多,复杂性带来的第一个问题就是命名管理问题再次遇到挑战,然后就是协同开发也被正式提上了议题,模块化正式走入台前。

 var a = 1;
//函数
function bindeEvent(){}
function addClass(){}
//命名空间
var obj1 = {
a:2,
foo:function(){}
}
var obj = {
a:2,
foo:function(){}
}
//闭包
(function($){
var a = 123;
function foo(){}
return {foo:foo}
})(jQuery);

模块化的在很大程度上与闭包的实现模式非常类似,传入闭包的参数可以看作是模块的引用,返回值可以看作是模块定义的接口,整个闭包就可以理解为一个模块,有差别的地方就是模块化是一个模块单独在一个js文件中实现、模块中使用的模块自身以外的参数和属性都必须依赖引入。

有了单独js文件和各种规范的标准接口,就能很好的实现了协同开发这问题,解决了前端开发越来越麻烦的复杂性,同时命名冲突问题也在模块的私有变量特性中迎刃而解。

二、commonjs规范

在commonjs官网的最上方有一句这样的描述:javascript: not just for browsers any more!翻译:javascript:不仅仅是针对浏览器了!最近两年在前端很火的nodejs就是commonjs规范的实现,而webpack是基于nodejs实现的,自然而然就是commonjs规范的实现。虽然我们后期在js的开发中不一定使用commonjs规范,但是我们需要使用webpack作为前端工程化的实现工具,还有基于nodejs的模块、插件、库,所以对于我们理解和应用其他技术很有帮助,所以对于commonjs的理解是有必要的。

可能说到这里,我们还不清除commonjs是个什么东西,这么来说,javascript官方定义的api只能构建基础的浏览器应用,也就是说javascript官方只实现了在浏览器环境中的api,如果来那javascript来做服务端应用程序,又或者是图形界面应用程序,还有命令行工具等就有些力不从心,2009年程序员Ryan Dahl创造了node,js项目,将javascript用于服务器端编程,这标志这javascript模块化开发的诞生,而commonjs就是这个模块的规范。

commonjs都有哪些规范呢?

1.commonjs的出发点:js没有模块系统、标准库较少、缺乏包管理工具;为了让javascript可以在任何地方运行,以达到JAVA、C#、PHP这些后台语言的开发能力。

2.commonjs规范的具体内容:

 一个文件就是一个模块;

 普通方式定义的变量、函数、对象都属于该模块内;

 通过require来加载模块;

 通过exports和modul.exports来暴露模块中的内容(接口);

3.所有代码都运行在模块作用域,不会污染全局作用域;模块可以多次加载,但只会在第一次加载的时候运行,然后运行结果就被缓存了,以后再加载就读取缓存里面的结果;模块的加载顺序按照代码的出现顺序同步加载。

4._dirname代表当前模块文件所在的文件夹路径,_filename代表当前模块文件所在文件夹路径+文件名。

5.require(同步加载基本功能):读取并执行一个js文件,然后返回该模块的exports对象,如果没有发现指定模块会报错。

6.模块内的exports:nodejs为每个模块提供了一个exposrts变量,其指向module.exports,相当于再模块头部加了这句代码:var exports = module.exports;在对外输出时,可以给exports对象添加方法,但不能直接赋值,因为这样会切断exports与module.exports的联系。

7.npm root -g 查看全局包安装位置,建议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、.json、.node后缀之后查找,如果存在文件则结束查找,如果不存在则进行下一条查找

  4).尝试将require的参数作为一个包来进行查找,读取目录下的package.json文件,取得Main参数指定的文件

  5).尝试查找该文件,如果存在则结束查找,如果不存在则进行第3条查找

  6).如果继续失败,则取出module.paths数组中的下一目录作为基准查找,循环第1-5个步骤

  7).如果继续失败,循环第1-6个步骤,直到module.paths中的最后一个值

  8).如果继续失败,则抛出异常

三、commonjs在前端模块化中的基本使用

Commonjs规范最开始就是为了将javascript运行在服务器环境下,所以采用了同步加载不同模块文件,适用于服务端。因为模块文件都存放在服务器的各个硬盘上,读取速度块,适合服务器,不适应浏览器。

而且浏览器不兼容Commonjs,原因是浏览器缺少module、exports、require、global是个环境变量。如果要使用的化需要工具转换,有时候还会用到global这个nodejs中的全局变量,相当于dom中的window变量。

在前端开发中使用Commonjs模块化规范:

1.定义文件结构:

//工作区间
-->modules//依赖模块
-->m1.js
-->m2.js
-->m3.js
-->demo.html//结构文本
-->index.js//主入口文件

依赖模块代码(m1.js):

 module.exports = {
msg:'m1',
foo:function(){
return this.msg;
}
}

依赖模块代码(m2.js):

 module.exports = function(){
return 'm2';
}

依赖模块代码(m3.js):

 // var exports = module.exports;在第博客二部分:commonjs规范中第六小点由说明
exports.foo = function(){
return 'ms';
}

主入口文件(index.js):

 var m1 = require('./modules/m1');
var m2 = require('./modules/m2');
var m3 = require('./modules/m3'); console.log(m1.foo());
console.log(m2());
console.log(m3.foo());

前面规范中说过在浏览器并不支持commonjs规范,主入口文件index.js肯定不能直接被demo.html结构文本使用,直接使用的话会报错;所以在要前端开发中使用commonjs规范的话就必须使用插件将commonjs模块化规范转换成浏览器识别的代码结构,在这之前系统上必须安装nodejs环境,这时候我们可以先在控制台中测试看看index.js的依赖是否成功:

 node -v //测试node环境是否安装成功,如果成功的话会在控制台打印出node的版本号
node index.js

打印结果:

这是在node环境下能够编译执行index.js,前面说过要想将commonjs模块化结构代码在浏览器中编译执行,得需要使用工具转换成浏览器能够编译执行的代码结构,这个工具就是Browserify,工具的官网:http://browserify.org/

下载安装成功是这样的:

在Browserify官网首页的使用介绍中有这样一句命令说明:

意思是将commonjs规范的main.js文件通过browserify转换成浏览器能够执行的bundle.js文件;那么我们就可以使用这个命令来将示例中的index.js转换成一个可以在浏览器使用的js文件(下面这句命令是要在命令窗口执行):

 browserify index.js -o bundle.js

这行命令执行完成后会在我们的工作区间生成一个bendle.js文件,这个文件就是通过browserify工具将基于commonjs规范的index.js入口文件及其依赖的m1.js、m2.js、m3.js转换生成的浏览器可以执行的js代码。

这时候我们可以将bundle.js引入到demo.html结构文件中进行执行:

<script src="bundle.js"></script>

打开页面-查看浏览器控制台:

在前端使用commonjs规范然后使用browserify转换成浏览器能执行的文件,全部过程演示完成;值得我们关注的是生成的bundle.js是什么?

从生成的代码来看,本质上就是将依赖的文件合并到了一个文件中,然后同样是采用闭包加对象属性实现的命名空间的代码管理方式,只不过这个过程我们交给了工具来实现,在我们的日常开发中,我们只需要关注我们自己的模块开发,不再需要去考虑全局命名冲突,代码管理问题。而且通过模块化开发带来的最大的好处就是代码的复用性特别方便,采用依赖模式然后使用工具转换,也解决了原来在结构文件中引入大量插件和库的问题,给代码瘦身的同时也降低了网络请求压力。特别是插件、库、组件之间的相互依赖关系带来的加载阻塞问题得到了很好的解决。

然后,在Browserify的官方首页使用介绍中有一个基于全局模块uniq的示例:

下载安装uniq模块:

npm install uniq

下载安装成功以后会在当前工作区间生成一个node_modules文件夹和一个packge-lock.json文件,各相关的原理在webpack博客中详细解析。然后,官网给出的代码放到我们示例代码中的index.js中:

 var unique = require('uniq');
var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];
console.log(unique(data));

然后,在控制台中再次编译一次index.js到bundle.js:

 browserify index.js -o bundle.js

然后刷新demo.html,查看浏览器控制台:

关于commonjs的实现原理等过段时间再来补充;

AMD、COM规范解析

js模块化入门与commonjs解析与应用的更多相关文章

  1. 一览js模块化:从CommonJS到ES6

    本文由云+社区发表 模块化是指把一个复杂的系统分解到一个一个的模块. 模块化开发的优点: (1)代码复用,让我们更方便地进行代码管理.同时也便于后面代码的修改和维护. (2)一个单独的文件就是一个模块 ...

  2. js模块化编程之CommonJS和AMD/CMD

    js模块化编程commonjs.AMD/CMD与ES6模块规范 一.CommonJS commonjs的require是运行时同步加载,es6的import是静态分析,是在编译时而不是在代码运行时.C ...

  3. js模块化编程之CommonJS和AMD/CMD!

    有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块. 但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套! 于是下面三个模块 ...

  4. js模块化AMD、CMD、ES6

    AMD CMD ES6模块化 各个模块化规范对比理解 一.AMD 在上一篇js模块化入门与commonjs解析与应用中详细的解析了关于commonjs模块化规范,commonjs采用的用同步加载方式, ...

  5. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  6. 再唠叨JS模块化加载之CommonJS、AMD、CMD、ES6

    Javascript模块化编程,已经成为一个迫切的需求.理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. Javascript社区做了很多努力,在现有的运行环境中,实现” ...

  7. JS模块化:CommonJS和AMD(Require.js)

    早期的JS中,是没有模块化的概念的,这一情况直到09年的Node.js横空出世时有了好转,Node.js将JS作为服务端的编程语言,使得JS不得不寻求模块化的解决方案. 模块化概念 在JS中的模块是针 ...

  8. js模块化编程之彻底弄懂CommonJS和AMD/CMD!

    先回答我:为什么模块很重要? 答:因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块.但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写 ...

  9. [转]js模块化编程之彻底弄懂CommonJS和AMD/CMD!

    原文: https://www.cnblogs.com/chenguangliang/p/5856701.html ------------------------------------------ ...

随机推荐

  1. B. Vanya and Books

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  2. eclipse导入工程报Invalid project description(转载)

    转自:http://blog.sina.com.cn/s/blog_a2eab3000101k3r7.html 昨天新搭建的环境,今天把以前的项目导入eclipse时报错: 说的是我导入的项目与wor ...

  3. hdoj1528【二分匹配】

    题意: 在一幅扑克牌里,有两个人在比大小,第二个人最多能赢第一个人几张牌. 思路: 这道题目用一下二分匹配还是很明显的. 那么就是建图似乎要麻烦一下,但还是很方便的.将扑克牌一次进行编号,然后牌面比他 ...

  4. poj1312dfs基础

    就是很简单的DFS-因为数据偏小,上去就是干了 #include <stdio.h> #include <string.h> #include <math.h> # ...

  5. bzoj 3173: [Tjoi2013]最长上升子序列【dp+线段树】

    我也不知道为什么把题看成以插入点为结尾的最长生生子序列--还WA了好几次 先把这个序列最后的样子求出来,具体就是倒着做,用线段树维护点数,最开始所有点都是1,然后线段树上二分找到当前数的位置,把这个点 ...

  6. Codeforces731D 80-th Level Archeology

    考虑将两个单词变成有序,我们可以得到一个或者两个旋转次数的区间. 然后考虑将两组单词变成有序,比如[l,mid]和[mid+1,r],对于mid和mid+1这两个单词我们可以求出使他们有序的旋转次数的 ...

  7. combobox级联检索下拉选择框

    1.效果图 2.前端 @{ ViewBag.Title = "Index"; Layout = null; @*自动筛选下拉框*@ <script src="~/S ...

  8. 基于 React-draft-wysiwyg 实现的 react 富文本编辑器组件 开箱即用

    工作中遇到了一个需要做图文详情 的富文本编辑的需求, 于是基于 React-draft-wysiwyg 实现了一个 纯组件, 目前支持 常规文本输入 外部链接图片 以及本地上传图片, 由于是纯组件, ...

  9. Opencv读写文件

    HSV也是用和RGB差不多的方式来表达像素,每个整形(integer) 向量分别表示一个B,G,R通道,其他的色彩空间,也用同样的方式来表示像素,只是取值范围和通道数目不同HSV的色彩空间的色度值范围 ...

  10. CF850 E. Random Elections

    题目传送门:CF 题目大意: 现有\(A,B,C\)三人参加竞选,有n个市民对其进行投票,每个市民心中对三人都有一个优先顺序(如市民\(i\)对三人的优先顺序为\(A-C-B\),则凡是有\(A\)的 ...