ES模块

504 阅读2分钟
ES中存在两种模块。ESM(ESModel)和CJS(CommonJS)。

ESM

导出
ESM中可以任意导出,但只允许有一个default导出。
export let c = 1;
export default {a:1,b:2};
导入
import x from '文件路径及名称';
import {c} from '文件路径及名称'; //导出非default方法,或者是import * as c from '文件路径及名称'; 此时c里有包含有所有的被导出对象内容,与CJS的exports对象类似。

CJS

导出
cjs模块比较简单,每个模块只有一个导出 module.export
module.exports = {a:1,b:2};
导入
const x = require( '文件路径及名称');
   注意:module.exports 与exports(把方法挂在exports上 如exports.c=123)都能导出,但是二者同时存在时module.exports才会被导出,而exports会被忽略。
   原因:在CJS里程序最终导出的还是module.exports,而exports只是对module.exports的一个全局引用,最初被定义为一个可任意添加属性的空对象。可以这么理解 exports.c 只是module.exports.c的简写。如果把exports设置为其他的,就打破了module.exports与exports之间的引用,此时的exports已经不再执行module.exports了
    解决方案:由上文可知,给exports赋值之后他们的引用已经发生了改变,那么让他们重新建立引用就行。如module.exports=exports即可,同时存在时 Object.assign(module.exports, exports);

异同

二者都能任意导出内容,ESM可以用export 来进行修饰;而CJS可以把内容添加到exports上,从而达到导出效果。
当ESM没有default时,import x from '文件路径及名称' ,x内容就会返回undefined,ESM是ES6之后才有的,而CJS在6之前就存在。
     
加载差异
CJS模块是对象(exports),是运行时加载,运行时才把模块挂在在exports上,加载模块其实就是查找对象属性;
ESM不是对象,是使用export和import进行导入导出的,此法为编译时加载,编译时需要export时便生成一个只读引用,等到运行时才会根据此引用去引用被加载的模块取值。
  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
解释:ES6是动态引用,不存在缓存,原始值变了,引用值也会跟着变;ES6模块不是对象,他的对外接口只是一个静态定义,在代码静态解析阶段就会生成。

AMD与CMD

二者都是CJS在浏览器端的解决方案。CJS是同步加载,而AMD、CMD是异步加载。
差异:
AMD是提前执行,CMD是延迟执行;
AMD推荐前置依赖,而CMD推荐依赖就近;