一.前端模块化问题
目前前端模块化规范比较多,有主张异步加载的AMD和CMD,还有同步加载的CommonJS,还有es6实现的esm,等等(以后再有新知识再补充),这里做一下总结
二.AMD和CMD实现
AMD和CMD都使用异步加载的方式,代表作如下
规范 | 代表作 |
---|---|
AMD | requireJS |
CMD | SeaJS |
我个人比较喜欢seajs,用起来方便好用
AMD和CMD都是运行时引入
三.CommonJS
CommonJS是同步加载的方式,适用于服务端.
因为服务端使用此标准加载的都是本地的文件,非常快,也就无所谓了
CommonJS是require进入一个对象,是非静态的,是在运行时才引入
四.esm
es module,也就是es6的模块化机制
esm是静态模块化实现,当使用import的时候,引入模块不是对象,而是通过export指定输出的代码,import引入输出的代码(只是一个内存引用地址,同时是不能改变的这个地址的,所以对象属性能修改,但是变量不能修改),能够实现静态检查,在编译之时就已经确定模块关系
esm默认使用严格模式
import具有提升效果,提升到模块的顶部,并要写在模块的顶层作用域内,不能写在if-else内或者函数内
这是esm不同于AMD , CMD , CommonJS 的地方.
五.对比和选择
1.AMD和CMD
AMD和CMD都是异步加载实现,但是AMD推荐依赖前置并先加载好(后来好像也变成了和CMD一样的策略了),而CMD推荐依赖就近加载 ; 个人比较喜欢seaJS
2.CommonJS和AMD/CMD
AMD/CMD是异步加载方案,适用于浏览器端
CommonJS是同步加载方案,适用于服务端,比如node
3.CommonJS和esm
CommonJS | esm |
---|---|
运行时加载 | 编译时输出接口(只读的,类似于const声明的变量) |
输出值得拷贝(输出后,模块内再变化就不能被外部感知,除非写函数获取) | 输出值得引用(或者说是输出内存地址的引用),模块内部的变化会被外部感知,如例1 |
/*-----------------------moduleB-------------------------------*/
let counter = 3;
function incCounter() {
counter++;
}
function getCounter() {
return counter;
}
module.exports = {
counter: counter,
incCounter: incCounter,
getCounter:getCounter
};
/*-----------------------moduleA-------------------------------*/
let B = require('./moduleB');
// 获取counter不会变化
console.log(B.counter); // 3
B.incCounter();
console.log(B.counter); // 3
// 写一个函数获取counter变量
console.log(B.getCounter()); // 3
B.incCounter();
console.log(B.getCounter()); // 4