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

模块化概念

在JS中的模块是针对单个文件的,即一个文件是一个模块,要使用这个模块就加载该文件即可。

CommonJS

node.js的模块系统,是参照CommonJS规范实现的。

定义模块和加载模块

在CommonJS中,有一个全局性方法require(),用于加载模块,而module.exports用于导出当前文件的模块。

假定有一个外部模块Utils.js,那么该模块需要这么写:

 // 定义类
function Utils(name) {
this._name = name;
} // 定义类方法
Utils.prototype.sayHi = function() {
console.log("Hi, I am " + this._name);
}; // 定义静态方法
Utils.add = function(a, b) {
return a + b;
} // 将类 Utils 作为当前文件的模块导出
module.exports = Utils;

加载模块并使用的方法如下:

 // 加载外部模块文件,位于当前文件夹下的 Utils.js,导入后该模块放入变量 Utils 中
var Utils = require('./Utils.js'); var obj = new Utils("Li Lei");
obj.sayHi(); // Hi, I am Li Lei console.log(Utils.add(10, 20)); //

可以导出为任意类型

我们就上面的例子稍加改动,Utils.js如下:

 function Utils(name) {
this._name = name;
}
Utils.prototype.sayHi = function() {
console.log("Hi, I am " + this._name);
};
Utils.add = function(a, b) {
return a + b;
}
module.exports = {version: 0.1, utils: Utils};

执行的js代码如下:

 var ex = require('./Utils.js');

 console.log(ex.version); // 0.1

 var obj = new ex.utils("Li Lei");
obj.sayHi(); // Hi, I am Li Lei console.log(ex.utils.add(10, 20)); //

我们可以发现可以导出任意的一个对象,而使用require导入的就是导出的那个对象。

不适用于浏览器

在Node.js中,require方法是同步执行的,即只有加载并解析之后,代码才会向下执行,但是在浏览器中,加载脚本是异步执行的。

AMD

有了服务器端模块以后,很自然地,大家就想要客户端模块。而且最好两者能够兼容,一个模块不用修改,在服务器和浏览器都可以运行。

但是浏览器并不适用CommonJS规范,因为服务器端同步加载不是一个问题,所有的模块都存放在本地硬盘,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,如果采用同步加载的策略,可能要等很长时间才能加载好文件,这段时间里浏览器会处于"假死"状态。

因此,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。这就是AMD规范诞生的背景。

概念

AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:

require([module], callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。

目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。下面我们主要就require.js来看看如何在浏览器里实现模块化。

Require.js

官网地址:http://www.requirejs.cn/

这个是非常流行的一个实现AMD规范的JS库,我们下载其最新版本(目前是2.1.11),我们下面用Require.js来实现上面CommonJS里的例子。

定义模块和加载模块

AMD规范里,定义模块和加载模块都和CommonJS规范不同,使用require加载模块但是带有回调函数,而定义模块则使用define函数。

我们先看看Utils模块的写法:

 define(function (){
// 定义类
function Utils(name) {
this._name = name;
} // 定义类方法
Utils.prototype.sayHi = function() {
console.log("Hi, I am " + this._name);
}; // 定义静态方法
Utils.add = function(a, b) {
return a + b;
} // 将类 Utils 作为当前文件的模块返回
return Utils;
});

加载和使用的方法如下:

 <html>
<head>
<title>Test</title>
<!-- 引入require.js文件 -->
<script src="require.js"></script>
<script>
// 配置各个模块地址
require.config({
    paths: {
      "Utils": "./js/lib/Utils"
    }
  }); // 如果模块地址都放在同一个文件夹中,可以用下面的简写方式
// require.config({
// baseUrl: "./js/lib",
  //   paths: {
  //     "Utils": "Utils"
  //   }
  // }); // 加载指定模块
require(["Utils"], function(Utils) {
// 模块加载完毕之后,模块中导出的对象会作为参数传入,再回调中直接使用即可 var obj = new Utils("Li Lei");
obj.sayHi(); // Hi, I am Li Lei console.log(Utils.add(10, 20)); // 30
});
</script>
</head>
<body>
</body>
</html>

多个模块的情况

我们定义的模块如果还依赖其它的模块,可以这么写:

 // 当前定义的模块依赖 Socket 模块
define(["Socket"], function (){
// 当前定义的模块依赖 Socket 及 Game 模块
define(["Socket", "Game"], function (){

加载模块时也可以加载多个模块:

 // 加载 Utils 和 Game 模块,加载好之后,对应模块的导出对象会在回调中作为参数分别传入
require(["Utils", "Game"], function(Utils, Game) {

更多地用法,可以参考官方文档。

总结一下

我们发现,CommonJS和AMD的写法无论是定义模块还是加载模块,都是存在差异的,但是模块内部的写法是基本一致的,所以通过一定的技巧,可以写出兼容两种标准的模块,如下:

 (function(golbal, factory){
// AMD
if(typeof define === "function" && define.amd)
define(factory);
// CommonJS
else if(typeof require === "function" && typeof module === "object" && module && module.exports)
module.exports = factory();
})(this, function(){
// 定义类
function Utils(name) {
this._name = name;
} // 定义类方法
Utils.prototype.sayHi = function() {
console.log("Hi, I am " + this._name);
}; // 定义静态方法
Utils.add = function(a, b) {
return a + b;
} // 将类 Utils 作为当前文件的模块返回
return Utils;
});

当然,知道了两种标准的差异之后,我们在使用时,也可以自己修改一个标准的模块为另一个标准可以支持的写法了。

另外,大部分类库都会提供多种模块格式的代码,比如AMD和CommonJS等格式,选择我们需要的格式即可。

JS模块化:CommonJS和AMD(Require.js)的更多相关文章

  1. Javascript模块化编程之路——(require.js)

    转自:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html Javascript模块化编程(一):模块的写法 随着网站逐渐变成&q ...

  2. r.js打包注意事项 r.js打包 这个是配合require.js打包的

    这个./代表的是当前文件的父目录....打包的资源一定要在这个父目录中下面才行,,,,一定一定,要放在这个目录一下才能被正确找到. 不然只是copy了一份一模一样的文件夹和文件过去,并不会处理压缩啥的 ...

  3. (转)JS模块化编程之AMD规范

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

  4. JS模块化编程之AMD规范(转)

    随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理.单元测试等等......开发者 ...

  5. 前端模块化 | 解读JS模块化开发中的 require、import 和 export

    本篇分为两个部分 第一部分:总结了ES6出现之前,在当时现有的运行环境中,实现"模块"的方式: 第二部分:总结了ES6出现后,module成为ES6标准,客户端实现模块化的解决方案 ...

  6. JS模块化工具require.js教程(一):初识require.js

    随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求 ...

  7. JavaScript模块化 --- Commonjs、AMD、CMD、es6 modules

    随着前端js代码复杂度的提高,JavaScript模块化这个概念便被提出来,前端社区也不断地实现前端模块化,直到es6对其进行了规范,下面就介绍JavaScript模块化. 这篇文章还是希望能给大家一 ...

  8. JavaScript模块化-CommonJS、AMD、CMD、UMD、ES6

    前言:模块化开发需求 在JS早期,使用script标签引入JS,会造成以下问题: 加载的时候阻塞网页渲染,引入JS越多,阻塞时间越长. 容易污染全局变量. js文件存在依赖关系,加载必须有顺序.项目较 ...

  9. 模块化-CommonJs、AMD、CMD、ES6

    在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题进行系统性的分解以之处理.模块化是一种处理复 ...

随机推荐

  1. 动态产生DataSource------待整理

    1. https://www.cnblogs.com/wsss/p/5475057.html https://www.cnblogs.com/jiligalaer/p/5418874.html htt ...

  2. 自适应阈值二值化之最大类间方差法(大津法,OTSU)

    最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU.它是按图像的灰度特性,将图像分成背景和目标2部分.背景和目标之间 ...

  3. 不一样的go语言-构建系统与构件系统

    前言   代码的最后一步是构建成计算机可识别的二进制数据,然后才得以在计算机上运行.如果你曾经写过有点规模(至少数十个以上独立的源文件,且需要依赖第三方包)C语言项目,必定对C语言项目的构建过程印象深 ...

  4. C# 设置MDI子窗体只能弹出一个的方法

    Windows程序设计中的MDI(Multiple Document Interface)官方解释就是所谓的多文档界面,与此对应就有单文档界面 (SDI), 它是微软公司从Windows .0下的Mi ...

  5. canvas学习-----1px线条模糊问题

    canvas有时候会出现1像素的线条模糊不清且好像更宽的情况,如下图: 这样的线条显然不是我们想要的. 这篇文章的目的就是弄清楚里面的原理,以及解决它. 大家都知道屏幕上最小的显示尺寸就是1像素,虽然 ...

  6. android studio 汉化 svn插件汉化。布局文件 属性 汉化 public.xml

    android studio 汉化 SvnBundle.properties D:\Android Studio\plugins\svn4idea\lib resources_en.jar\org\j ...

  7. Scratch儿童项目式编程—捉迷藏游戏 Scratch children project programming - hide-and-seek game

    Scratch儿童项目式编程—捉迷藏游戏 Scratch children project programming - hide-and-seek game 作者:韩梦飞沙 Author:han_me ...

  8. 10.29 正睿停课训练 Day11

    目录 2018.10.29 正睿停课训练 Day11 A 线段树什么的最讨厌了(思路 DFS) B 已经没有什么好害怕的了(差分 前缀和) C 我才不是萝莉控呢(DP 贪心 哈夫曼树) 考试代码 A ...

  9. 解决boostrap中,iframe渲染下,苹果手机横向无法显示剩余内容问题

    描述: 问题解决了,采用的手势拖动显示剩余内容,并不是有了横向滚动条 在head标签中加入 <head> <meta charset="utf-8"> &l ...

  10. php中call_user_func 与 call_user_func_array的使用

    call_user_func()是利用回调函数处理字符串,call_user_func_array是利用回调函数处理数组. // 1. 调用自定义函数 function test($a, $b) { ...