目前主流的 JavaScript 模块化规范有 CommonJS,AMD,CMD,ES6 Module 四种规范
CommonJS
CommonJS 主要应用于服务端 (node),其主要内容为:一个单独的文件就是一个模块,每一个模块都是一个单独的作用域,模块必须通过 module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前的模块的作用域中
//node环境编译
//a.js
let b = 0
exports.a = () => {
console.log('a')
b+=1
}
exports.b = () => {
console.log(b)
}
//b.js
const {a, b} = require('./a');
a() //a
module.exports.b = () => {
console.log('b')
a() //a
}
//c.js
const bf = require('./b').b;
var {a, b} = require('./a');
a() //a
b() //2
bf() //b
b() // 3
var {a, b} = require('./a');
b() // 3 读取的是缓存
加载模块
模块加载的顺序,按照其在代码中出现的顺序,同步加载的方式加载。
缓存机制
NodeJs 对引入过的模块都会进行缓存,以减少二次引入时的开销。不同的是,浏览器仅缓存文件,而在 NodeJs 中缓存的是编译和执行后的对象。
加载机制
输入的是被输出的值的拷贝。一旦输出一个值,模块内部的变化就影响不到这个值。
AMD
异步模块加载机制,它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句都定义在一个回调函数中,等到依赖加载完成之后,这个回调函数才会运行。
AMD 的诞生,就是为了解决
- JavaScript 文件中的异步加载,避免网页失去响应
- 管理模块之间的依赖性,便于代码维护和编写
通过 define(id?: String, dependencies?: String[], factory: Function|Object) 来定义模块
- id : 模块名称
- dependencies : 依赖模块
- factory : 回调函数或者输出对象
通过
require([module], callback)来引入模块 - modeul : 依赖模块
- callback : 回调函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./require.js" data-main="main.js"></script>
</body>
</html>
//a.js
define(function() {
var sayHi = () => {
console.log("Hi-a")
}
return {
//返回接口
sayHi:sayHi,
a:1
}
})
//b.js
define(function() {
var sayHi = () => {
console.log("Hi-b")
}
return {
sayHi:sayHi,
b:2
}
})
//c.js
define([
//依赖模块
'./a.js',
'./b.js'
], function(a, b) {
console.log(a,b)
a.a++
b.b++
return {
c: a.a + b.b
}
});
//main.js
require(["./a","./b","./c.js"], function(a,b,c) {
console.log(a,b,c)
a.sayHi() //Hi-a
b.sayHi() //Hi-b
console.log(c.c) //5
})
CMD
CMD (Common Module Definition) 通用模块定义,浏览器端的实现有 SeaJS,跟RequireJS一样动态创建异步的 script 标签。区别在于AMD 推崇一开始就加载所有的依赖,CMD推崇有需要的地方才进行依赖加载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./sea.js"></script>
<script>
seajs.config({
alias:{
'main':'./main.js'
},
});
seajs.use(['main'],function(main) {
main.sayHi()//a-b-c
});
</script>
</body>
</html>
//a.js
define(function(require, exports) {
var a = 'a'
exports.a = a
});
//b.js
//SeaJS 会首先用正则匹配出代码里面所有的 require 语句,拿到依赖,然后依次加载,加载完成再执行回调函数
define(function(require, exports) {
var a = require('./a.js').a
var b = a + '-b'
exports.b = b
});
//c.js
define(function(require, exports) {
var b = require('./b.js').b
var c = b + '-c'
exports.c = c
});
//main.js
define(function(require, exports) {
var c = require('./c.js').c
exports.sayHi = function(){
console.log(c)
}
});
ES Module
ES Module 是 ES6 引入的模块化功能,主要由 export 和 import 两个命令构成,export 用于规定模块对外接口,import 用于输入其他模块提供的功能。
//a.js
//导出变量
export var a = 1
//导出函数
export function b(){
}
//导出类
export class C {
constructor(){
}
}
var d = 100
//导出对象
export {
d
}
//重命名导出
export { d as e}
//默认导出,一个模块只能有一个默认导出
export default d
//b.js
import { a } from "./a.js";