开头总结
1 相同点
都是前端模块化的一种
2 不同点
- 前者利用exports和module.exports导出数据,用require导入;后者利用export和export default导出,利用import导入
- 前者是动态化加载,可以放在块级作用域中使用;后者是静态加载,在编译的时候就处理了。
- 前者导出的数据如果是基本数据类型,导出的是拷贝,引用数据类型的话则是引用。后者导出的都是原数据的引用。
前者可以解决循环引用的问题,后者不能解决
不同点分析
第一点
// c.js exports.name = "mike"; module.exports = { name: "mike" } // d.js let c = require('./c'); console.log(c); // { name: 'mike' }
对于ES6module要在package.json中增加"type": "module"或者采用.mjs扩展名,下面演示代码采用后者
// b.mjs export let a = "hello world"; const b = "这是b" export default b; // a.mjs import b, {a} from './b.mjs' console.log(a); // hello world console.log(b); // 这是b // 对于export default的变量,引入的时候不需要加{},export的变量需要加{}
第二点
CommonJS如下
只改变d的内容// d.js function say() { let c = require('./c'); console.log(c); } say(); // { name: 'mike' }
ES6module如下
只改变a.mjsfunction say() { import b, {a} from './b.mjs' console.log(a); console.log(b); } say(); // 报错
第三点
对于CommonJS
// c.js module.exports = "hello world" // d.js let a = require('./c') a = "hi, world" console.log(a); let b = require('./c') console.log(b); //hi, world // hello world // 引用数据类型的情况 // c.js exports.name = "hello, world" // d.js let a = require('./c') a.name = "hi, world" console.log(a); let b = require('./c') console.log(b); // { name: 'hi, world' } { name: 'hi, world' }
对于ES6module
// a.mjs let a = "hello, world"; export {a} // b.mjs import {a} from './a.mjs' a = "hi, world" console.log(a); // 报错,Assignment to constant variable.
因为ES6module导出的是引用,默认导出的是const变量,所以禁止更改其值,修改了则报错.
解决循环引用
1 CommonJS中采用了缓存,对于已经一个模块,require()函数先去缓存中寻找是否已经加载,如果加载了直接从缓存中取;否则先缓存该模块,再去执行,(注意顺序) 有了缓存很好的解决了循环引用的问题。
如下例子存在main.js c.js d.js三个文件, c和d互相引用,main引用c和d
// c.js
let d = require('./d');
console.log("这是c");
// d.js
let c = require('./c')
console.log("这是d");
// main.js
let c = require('./c')
let d = require('./d')
console.log("这是main");
// 结果
// 这是d
// 这是c
// 这是main
// 而且发现d仅执行了一次,验证了缓存的说法, 当执行到c的第一行的时候,c已经被缓存了,进入d执行第一行的时候,是从缓存中取的c,此时c只是被缓存了还未被执行。
2 ES6module对于循环引用会报错。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。