Loading...
墨滴

浪淘沙

2021/04/11  阅读:26  主题:前端之巅同款

ES6模块和CommonJS模块相互转换

ES6模块和CommonJS模块相互转换

写在前面

之所以写这样一个专题,是因为我最近在研究VSCode的插件开发的过程中,习惯性的使用了ES6的模块规范,也就是使用了export import 关键字,结果插件调试的时候空值台报了一个import 关键字相关的错误。自行梳理了一下VSCode插件的技术栈,得知vscode是基于Electron开发的,使用的是nodejs。 因此模块规范采用的是CommonJS模块规范。所有导致上了的错误,定位到问题之后,解决办法就非常简单了,那就是将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.

注意事项

  1. CommonJS 模块导出的其实是一个对象,相当于一开始module.exports = {} 是一个空对象,然后在这个空对象里面事项了属性和方法,并将整个对象导出。
  2. 在导入一个模块时,CommonJS导入的是一份导出值得拷贝,允许对导入的值进行修改。
  3. ES6导出的则是值得动态映射,且该值是只读的。(一改全改,但只能在模块内部改动)

本文同步发布于G众号"前端知识营地",点击关注,获取更多优质有趣的内容。

浪淘沙

2021/04/11  阅读:26  主题:前端之巅同款

作者介绍

浪淘沙