ES6模块和CommonJS模块相互转换
写在前面
之所以写这样一个专题,是因为我最近在研究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导出的则是值得动态映射,且该值是只读的。(一改全改,但只能在模块内部改动)
本文同步发布于G众号"前端知识营地",点击关注,获取更多优质有趣的内容。
(完)