ES6模块和CommonJS模块相互转换
这里写目录标题
- ES6模块和CommonJS模块相互转换
- 写在前面
- ES6模块和CommomJS模块的异同
- 转换原理
- 转换案例
- 注意事项
写在前面
之所以写这样一个专题,是因为我最近在研究VSCode的插件开发的过程中,习惯性的使用了ES6的模块规范,也就是使用了export
import
关键字,结果插件调试的时候空值台报了一个import
关键字相关的错误。自行梳理了一下VSCode插件的技术栈,得知vscode是基于Electron开发的,使用的是nodejs。 因此模块规范采用的是CommonJS模块规范。所有导致上了的错误,定位到问题之后,解决办法就非常简单了,那就是将ES6模块,转换为CommonJS模块。下面就简单说说转换原理和案例。
为获得更好的阅读和观看体验,推荐访问我在wolai的读书笔记。ES6模块和CommonJS模块相互转换
ES6模块和CommomJS模块的异同
- CommonJS
- 最初为服务端设计,node.js版本。
- 每个文件即使一个文件,用于独立的作用域。
- 导出是一个模块向外暴露自己的唯一方式。CommonJS中通过module.exports导出模块中的内容。
- CommonJS中使用require进行模块的导入。
如果导入的模块是第一次被加载,这时会首先执行该模块,然后导出执行后的内容。
如果模块曾经被加载过,则直接导出第一次加载时执行后的内容。(相当于是一个静态值了)
- ES6模块
- 每个文件作为一个模块,每个模块拥有独立的作用域。
- 通过exports导出
命名导出:exports { a, b }
默认导出:exports default a; (只能导出一个对象)
- 通过**import **导入,默认导出的变量,导入时可以随意命名,命名导出方式,导入时名称必须一致,可以使用as 重命名。
- CommonJS 与ES6模块的区别
- CommonJS 对模块依赖的解决是动态的,而ES6模块是静态的。
- 模块导入时:CommonJS是值拷贝,而ES6则是只读的动态映射。
- 动态:模块的依赖关系建立在代码运行阶段
- 静态:模块的依赖关系建立在代码编译阶段
- CommonJS引入模块时可以动态指定,例如使用if等条件语句引入不同的模块。
- ES6模块相比CommonJS的优势
- 死代码检测和排除:通过静态分析工具检测出哪些模块没有被调用过。从而在打包时去掉未使用的模块,以减少资源包的体积。
- 模块变量类型检查:JS是动态类型语言,不会在代码执行前检查类型错误,ES6模块属于静态类型模块,有助于确保模块之间的传递的值或者接口类型是正确的。
- 编译器优化:CommonJS无论采用哪种方式,导入的都是一个对象,而ES6模块直接导入变量,减少应用层级,程序效率更高。
转换原理
可以看到无论是ES6还是CommonJS 对模块的定义都是一致的,每个文件即是一个模块,拥有独立的作用域。不同点在于ES6模块通过export
导出,通过import
导入;而CommonJS则是通过module.exports
导出,通过require
导入。那么是不是说只需将导出和引入的语法关键字改一下就可以了呢?下面就通过实践来看一看吧。
转换案例
下面通过将ES6模块转换为CommonJS模块进行演示,反之则是CommonJS转ES6模块。
- 案例1 export default
ES6模块
// a.js
export default function () {
console.log("hello world");
}
// index.js
import a from "./a.js"; // 默认导出可以自由命名
a();
转换为对应的common JS模块
// a.js
module.exports = function(){
console.log("hello world");
}
// index.js
const a = require("./a.js");
a();
- 案例2 export { a, b }
ES6 模块
// a.js
const a = {
name: "mingyong.g",
};
const fun = function () {
console.log("hello world");
};
export { a, fun };
// index.js
import { a, fun } from "./a.js"; // 导入时名字必须和导出时的命名一致
console.log(a);
fun();
CommonJS模块
// a.js
const a = {
name: "mingyong.g",
};
const fun = function () {
console.log("hello world");
};
module.exports = {
a,
fun,
};
// 或者使用下面这种方式导出
module.exports.a = a;
module.exports.fun = fun;
// index.js
const module = require("./a.js") // 导入的是一个整体,是{a:a,fun:fun}形式
const a = module.a;
const fun = module.fun;
注意:上面的CommonJS模拟的是node.js环境,故通过module.exports导出CommonJS模块,而非直接使用exports.
注意事项
- CommonJS 模块导出的其实是一个对象,相当于一开始
module.exports = {}
是一个空对象,然后在这个空对象里面事项了属性和方法,并将整个对象导出。 - 在导入一个模块时,CommonJS导入的是一份导出值得拷贝,允许对导入的值进行修改。
- ES6导出的则是值得动态映射,且该值是只读的。(一改全改,但只能在模块内部改动)