前端模块化的一些总结

时间:2023-02-04 05:14:38

一.前端模块化问题

目前前端模块化规范比较多,有主张异步加载的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