javascript复制下载function add(a, b) {
return a + b;
}
module.exports = { add };然后在另一个文件里这样引入:
javascript复制下载const calc = require('./calc.js');
console.log(calc.add(1, 2)); // 输出3这种同步加载的方式在服务端很合适,因为Node.js的模块都在本地磁盘,读取速度很快。但要是放在浏览器环境,这种同步机制就会导致页面卡顿,因为每个模块都要等前一个加载完才能继续。
ES6 Module则是JavaScript语言层面的模块系统,现代浏览器都已经原生支持了。它的语法更加简洁,使用export导出,import导入。还是那个计算器例子,用ES6 Module可以这样写:
javascript复制下载export function add(a, b) {
return a + b;
}引入的时候:
javascript复制下载import { add } from './calc.js';
console.log(add(1, 2)); // 输出3ES6 Module最大的特点是静态化,也就是说import和export命令只能在模块的顶层,不能在条件语句中使用。这种设计使得在编译阶段就能确定模块的依赖关系,为后续的Tree Shaking(无用代码消除)提供了可能。
说到两者的区别,加载时机是个关键点。CommonJS是运行时加载,也就是在代码执行到require语句的时候才会加载模块。而ES6 Module是编译时加载,这样就能在打包阶段进行优化。另外,CommonJS输出的是值的拷贝,而ES6 Module输出的是值的引用。举个例子:
javascript复制下载// CommonJS
// counter.js
let count = 0;
function increment() {
count++;
}
module.exports = { count, increment };
// main.js
const { count, increment } = require('./counter');
console.log(count); // 0
increment();
console.log(count); // 0,值没变而ES6 Module就不一样:
javascript复制下载// counter.js
export let count = 0;
export function increment() {
count++;
}
// main.js
import { count, increment } from './counter';
console.log(count); // 0
increment();
console.log(count); // 1,值变了这是因为ES6 Module是动态绑定,导入的变量会随着导出模块内部值的变化而变化。
在实际开发中,我们经常需要混用两种模块系统。比如在Node.js环境中使用ES6 Module,可以在package.json里设置"type": "module"。反过来,如果想在ES6 Module中引入CommonJS模块,直接用import语句就可以了,Node.js会自动处理转换。
循环依赖的处理也是个值得注意的问题。CommonJS在处理循环依赖时比较“聪明”,遇到还没执行完的模块会返回部分结果。而ES6 Module由于是静态结构,能够更好地处理循环依赖,但也要注意导入的变量是否已经初始化。
现在的前端项目大多会用打包工具,比如Webpack、Rollup这些。它们都能很好地处理两种模块系统,甚至允许在同一个项目中混用。不过从长远来看,ES6 Module肯定是趋势,毕竟是语言标准。但在Node.js环境下,CommonJS短期内还不会被完全取代,毕竟现有的生态太庞大了。
选择哪种模块系统,关键要看具体场景。如果是纯前端项目,优先考虑ES6 Module;如果是Node.js后端项目,CommonJS可能更合适;如果是同构应用,那就要根据构建工具的能力来做选择了。不管选哪种,最重要的是保持项目内部的一致性,别一会儿用这种,一会儿用那种,那样只会增加维护成本。
模块化看起来是个技术细节,实际上直接影响着项目的可维护性和开发效率。理解清楚不同方案的特点,才能在合适的场景做出合适的选择。毕竟,好的代码组织方式能让后期的维护工作轻松不少,这个道理大家都懂。
CommonJS与ES6模块对比解析

被折叠的 条评论
为什么被折叠?



