开始总结1相同点是前端模块化的一种2不同点是前者使用exports和module.exports导出数据,使用require导入;后者使用export和exportdefault导出,使用import导入前者是动态加载,可以在块级范围内使用;后者是静态加载,在编译时处理。前者导出的数据如果是基本数据类型就是副本,如果是引用数据类型就是引用。后面的导出都是对原始数据的引用。前者可以解决循环引用问题,后者不能解决差异分析。第一点//c.jsexports.name="mike";module.exports={name:"mike"}//d.jsletc=require('./c');console.log(c);//{name:'mike'}对于ES6module,在package.json中添加"type":"module"或使用.mjs扩展名,下面的演示代码使用后者//b.mjsexportleta="helloworld";constb="thisisb"exportdefaultb;//a.mjsimportb,{a}from'./b.mjs'console.log(a);//你好worldconsole.log(b);//这是b//导出默认变量,导入时不需要加{},导出变量需要加{}。CommonJS的第二点如下,只改变d内容//d.jsfunctionsay(){letc=require('./c');控制台日志(c);}说();//{name:'mike'}ES6module如下仅更改a.mjsfunctionsay(){importb,{a}from'./b.mjs'console.log(a);console.log(b);}说();//第三点报错是针对CommonJS//c.jsmodule.exports="helloworld"//d.jsleta=require('./c')a="hi,world"console.log(a);letb=require('./c')console.log(b);//hi,world//helloworld//引用数据类型//c.jsexports.name="hello,world"//d.jsleta=require('./c')a。name="hi,world"console.log(a);letb=require('./c')console.log(b);//{name:'hi,world'}{name:'hi,world'}forES6module//a.mjsleta="hello,world";导出{a}//b。mjsimport{a}from'./a.mjs'a="hi,world"console.log(a);//错误,赋值给常量变量。因为ES6module导出引用,默认导出的是const变量,所以禁止修改它的值,修改了会报错。解决循环引用1CommonJS使用缓存。对于一个已经存在的模块,require()函数首先会去缓存中查找是否已经被加载。如果加载,则直接从缓存中取出;否则,它将首先被缓存。再次执行这个模块(注意顺序)缓存解决了循环引用的问题。下面的例子有三个文件:main.jsc.jsd.js,c和d互相引用,main引用c和d//c.jsletd=require('./d');console.log("Thisisc");//d.jsletc=require('./c')console.log("Thisisd");//main.jsletc=require('./c')letd=require('./d')console.log("Thisismain");//结果//Thisisd//Thisisc//Thisismain//发现d只是执行一次,验证缓存语句。当第一行c执行时,c已经被缓存了。输入d执行第一行时,是从缓存中取出的c。这个时候c只是缓存了,并没有被执行。2ES6module会报循环引用错误。
