浅析javascript中的export/import 与commonjs的require/exports,以及export default的问题

布满荆棘的人生 2022-12-28 06:17 457阅读 0赞

我想先解释一下commonjs(cjs)的导出导入概念,结合他来理解es6 module(esm)更好理解。

在commonjs,大部分情况就是nodejs中,定义导出的时候其实就是exports对象,比如

  1. module.exports = { a: 1, b: 2};
  2. // 或者
  3. module.exports.a = 1;
  4. module.exports.b = 2;

以上,其实module.exports本身是一个Object,他作为commonjs规范下模块的默认(default)导出,这里可以理解为相当于ES6的export default

但值得注意的是,commonjs中仅仅支持这一种默认导出。不支持类似于ES6中:

  1. export const a = 1;
  2. export const b = 2;

以上是具名导出(named export), 也就是说如果你想使用’具名导入’的方式去导入一个commonjs的包,是会报错的。因为cjs根本就不支持。

  1. // module1.cjs
  2. module.exports = { a:1};
  3. // module2.mjs
  4. // const {a} = require('./module1') // 可以执行,因为前边是解构语法
  5. import { a} from './module1.cjs' // 不可以执行,因为这个named import,不是解构。

上述代码执行报错如下:

  1. SyntaxError: Named export 'a' not found. The requested module './module1.cjs' is a CommonJS module, which may not support all module.exports as named exports.
  2. CommonJS modules can always be imported via the default export, for example using:
  3. import pkg from './module1.cjs';
  4. const { a} = pkg;

这个报错非常的人性化,清楚的解释了你有一个语法错误,也就是import {a} from './module1.cjs'这种导入会去被导入的包中寻找具名的导出,就是export const a = 1这种导出。但cjs是不支持的,所以报错了。

到这里,我想简单总结下,在模块导入导出的过程中,对于cjs和esm,他们支持两组导出:

  • module.exports / export defalut对应着 require() / import anyName from './'
  • 具名导入导出(named export) export const a; export const b 对应着 import {a, b} from './'

网上有文章说,最好不要使用export default,究其原因是因为这个会引起歧义,比如以下这种场景:

  1. //module1.js
  2. export default { a: 1, b: 2};
  3. // module2.js
  4. import { a, b} from './a'

上述代码是错误的。因为module2中的语法不是解构,而是去寻找module1中的具名导出。而实际上module1中是没有的。所以会报出undefined。

实际上他是以下语法的简写

  1. import {a as a, b as b} from './module.mjs'

不是下面的简写

  1. import {a: a, b: b} from './module.mjs'

如果你真的想去解构,应该这样写:

  1. import module1 from './module.mjs'
  2. const { a, b} = module1;

所以倒不是不让用export default,而是需要注意到潜在的问题。

最后,在模块导出的时候,你可以写一种兼容的写法,也就对于导入者来说,他怎么导入都不会错。

  1. const api = {a, b}
  2. // 有默认导出
  3. export default api;
  4. // 也有具名导出
  5. export const {a, b} = api;

发表评论

表情:
评论列表 (有 0 条评论,457人围观)

还没有评论,来说两句吧...

相关阅读