JavaScript模块化最全总结
没有模块化规范的时候
在没有CommonJS,AMD,CMD等规范的时候,人们为了让代码模块化,采用了下面这个链接里的方法:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
CommonJS
NodeJS 是 CommonJS 规范的实现,webpack 也是以 CommonJS 的形式来书写。CommonJS 是一种只适用于 JavaScript 的静态模块化规范。只适用于 Node.js 开发,但是不适合浏览器环境。
原因:
- 浏览器环境的前端资源不仅仅是 JavaScript ,还包括 CSS 、图片等, CommonJS 无法处理 JavaScript 以外的资源。
- CommonJS 所有模块均是同步阻塞式加载,无法实现按需异步加载。
特点:
- 同步加载;
- 主要用于服务器端,不适合前端;
- 在服务器端,模块的加载是运行时同步加载的;
- 在浏览器端,无法直接运行在浏览器端上,需要通过工具转换成标准的 ES5 ;
- 所有代码都运行在模块作用域,不会污染全局作用域;
- 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存;
- 模块加载的顺序,按照其在代码中出现的顺序。
实现:
NodeJS
使用:
加载模块/引入模块:
如果是第三方模块,xxx
为模块名;如果是自定义模块, xxx
为模块文件路径。
require(xxx)
暴露模块:
module.exports = value
// 或
exports.xxx = value
加载机制:
输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
AMD
AMD,异步模块定义。浏览器的模块,不能采用“同步加载”,只能采用“异步加载”,因此 AMD 产生了。与 CommonJS 最大的不同在于它采用异步的方式去加载依赖的模块。
特点:
- 专门用于浏览器端;
- 模块的加载是异步的, 模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行;
- 依赖前置。
优点:
- 可在不转换代码的情况下直接在浏览器中运行;
- 可异步加载依赖;
- 可并行加载多个依赖;
- 代码可运行在浏览器环境和 Node.js 环境下。
缺点:
- JS 运行环境没有原生支持 AMD,需要先导入实现了 AMD 的库后才能正常使用。
使用:
加载模块/引入模块:
require([module], callback);
// 例子
require(['moduleA', 'moduleB', 'moduleC'], function(moduleA, moduleB, moduleC) {
// ...
});
定义模块:
模块必须采用特定的 define()
函数来定义。
- 定义的模块不依赖其他模块
// math.js
define(function() {
var add = function(x, y) {
return x + y;
};
return {
add: add
};
});
- 定义的模块依赖其他模块,那么
define()
函数的第一个参数,必须是一个数组,指明该模块的依赖性。
define(['myLib'], function(myLib) {
function foo() {
myLib.doSomething();
}
return {
foo: foo
};
});
实现:
- RequireJS
RequrieJS 是一个工具库,只要用于客户端的模块。它的模块管理遵守 AMD 规范。RequireJS 的基本思想是,通过 define
方法,将代码定义为模块;通过 require
方法,实现代码的模块加载。出自 dojo 加载器的作者 James Burke
- 依赖前置。RequireJS 会先尽早地执行(依赖)模块,相当于所有的 require 都被提前了,但是模块的执行顺序不一定是 require 的顺序。
- RequireJS 引入的文件(模块),只会解释执行一次,所以引入的模块也可用作全局变量。
- RequireJS 要求,每个模块是一个单独的 js 文件。
- curlJS
CMD
特点:
- 依赖就近
- 在浏览器端使用
- 异步加载
- 整合了 CommonJS 和 AMD 规范的特点
使用:
定义模块:
- 定义没有依赖的模块
define(function(require, exports, module) {
exports.xxx = value
module.exports = value
})
- 定义有依赖的模块
define(function(require, exports, module) {
// 引入依赖模块(同步)
var module2 = require('./module2')
// 引入依赖模块(异步)
require.async('./module3', function (m3) {
})
// 暴露模块
exports.xxx = value
})
加载/使用模块:
define(function (require) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
实现:
- SeaJS
- 出自玉伯
- 懒执行
- SeaJS 只会在真正需要使用(依赖)模块时才执行该模块
- SeaJS 执行模块的顺序是严格按照模块在代码中出现(require)的顺序。
- 依赖就近
## ES6模块化 ES6 模块化是 ECMA 提出的 JavaScript 模块化规范,它在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代 CommonJS 和 AMD 规范,称为浏览器和服务器通用的模块解决方案。
**特点:**
- 每一个模块只加载一次,每一个 js 只执行一次,如果下次再去加载同一个文件,直接从内存中读取。一个模块就是一个单例,或者说就是一个对象。
- 每一个模块内声明的变量都是局部变量,不会污染全局作用域。
- 模块内部的变量或者函数可以通过 export 导出。
- 一个模块可以导入别的模块。
使用:
导出模块:export
命令用于规定模块的对外接口。
引入模块:import
命令用于输入其他模块提供的功能。
例子:
// 定义模块math.js
var basicNum = 0;
var add = function(a, b) {
return a + b;
};
export { basicNum, add };
// 引用模块
import { basicNum, add } from './math';
function test(ele) {
ele.textContent = add(99 + basicNum);
}
ES6模块 VS CommonJS
模块输出 | 加载方式 | |
---|---|---|
CommonJS | 值拷贝 | 对象 |
ES6 | 引用(符号链接) | 静态解析 |
注意:由于 ES6模块化 目前无法在浏览器中执行,所以,我们只能通过 babel 将不被支持的 import
编译为当前受到广泛支持的 require
。
UMD
特点:
- UMD 是 AMD 和 CommonJS 的糅合
- UMD 先判断是否支持 Node.js 的模块(exports)是否存在,存在则使用 Node.js 模块模式;再判断是否支持AMD(define)是否存在,存在则使用 AMD 方式加载模块。
- 常用的场景就是当你封装的模块需要适配不同平台(浏览器、node.js)
原文链接:js模块化