前言
一开始js做的交互很简单,没有模块化的概念,随着前端交互功能的复杂化,js文件的代码量变得越来越大,也就衍生出模块化的概念。
模块化历程
CommonJs
出现原因:nodejs为了解决模块化问题设计的,一个文件就是一个作用域,拥有自己的变量和方法。
通过require和moudle.exports实现,CommonJs的输出是值的拷贝,外部引入该文件的变量和方法时,该模块代码只有在第一次运行的时候会被加载,运行结果会被缓存下来,外部的下次引用都是从缓存中直接读取,如下:
// a.js文件
var num = 1;
function updateNum(){
num++;
}
moudle.exports={
num:num,
updateNum:updateNum
};
// b.js文件
var num = require('./a').num;
var updateNum = require('./a').updateNum;
console.log(num); // 1
updateNum();
console.log(num); // 1 因为num只是对a模块中的num的值的拷贝,而updateNum修改的是a模块中的num
AMD
出现原因:nodejs是在服务端运行,文件都是存在磁盘,不需要发起请求获取,所以CommonJs的模块化加载是同步执行的。但是用于浏览器环境显然不合适,script标签引入脚本是异步的,所以衍生出AMD,AMD能够异步的加载模块脚本。
实现库是require.js,通过define和require实现,模块的加载不影响后面语句的执行,所有依赖该模块的语句,都会放在一个回调函数当中,当模块加载完毕才执行该回调函数。
define:用于定义模块,需要3个参数,第一个参数是模块标识,没传默认为本文件名,第二个参数是数组,存放该模块的依赖,第三个参数是一个函数,模块初始化时候执行,只执行一次。
require:用于读取其他模块,需要2个参数,第一个参数是数组,放需要加载模块的集合,第二个参数是回调函数,等模块加载完执行。
// a.js文件
define(['dependency'],function(){
var num = 1;
function updateNum(){
num++;
}
return {
num:num,
updateNum:updateNum
};
})
// b.js文件
require(['a'],function(obj){
var num = obj.num;
console.log(num);// 1
})
CMD
CMD与AMD区别在于,实现库是sea.js,AMD推从依赖前置,CMD推崇依赖就近。
ES
ES的模块化加载通过export、export default和import实现, ES的输出是值的引用。b模块引用了a模块暴露的updateNum方法执行后,修改了a模块中的num值,b模块也会获取到最新的num值,如下。
// a.js文件
const num = 1;
const updateNum = ()=>{
num++;
}
export { num, updateNum };
// b.js文件
import { num, updateNum } from './a.js'
console.log(num);// 1
updateNum();
console.log(num);// 2
CommonJs和ES的区别
1、CommonJs的模块输出是值的拷贝,ES的模块输出是值的引用。
2、CommonJs模块是运行时加载,ES模块是编译时输出。
3、CommonJs的require()是同步加载模块,会阻塞后面语句的执行,ES的import是异步加载模块,有一个独立的模块依赖解析阶段。