我个人是这么理解的:import * as xx from 'xx' 导入的是一个模块的全部导出内容(具名导出和默认导出),而 import xx from 'xx' 导入的只是一个模块的默认导出(不包括具名导出部分)。
其实我们知道在 CommonJs 中,与导出相关的 API 只有两个:exports 和 module.exports。 如果对 module.exports 进行赋值的话,其实 exports 也会被覆盖。更近一步地讲,在初始状态下,exports 与 module.exports 其实就是同一个对象。
所以 module.exports 导出的其实就是模块的全部内容。那么在 esModule 中想要导入 module.exports,也就是模块的全部内容,需要使用导入全部内容的导入方式,也就是 import * as xx from 'xx'。
关于 import { a } from 'xx' 怎么理解呢?
我个人是这么理解的:import { a } from 'xx' 导入的是一个模块的部分导出内容。所以这种方式可以导入 exports.a,也可以导入 module.exports = { a: 1, b: 2 } 中的 a 部分。
在 CommonJs 中导入 esModule 导出的内容
我们知道其实 CommonJs 只有一种导入方式,也就是导入模块的全部内容:require('xx')。一般我们会用一个变量或者解构赋值的方式来接收 require('xx') 的结果,然后通过这个(些)变量来访问模块的导出内容。
所以在 CommonJs 中导入 esModule 导出的内容,也就只有一种导入方式,那就是导入 esModule 模块的全部内容。也就是 const m = require('xx') 中 m 对象包括了 esModule 模块的全部内容。
值得注意的是:esModule 中的默认导出部分依附在了 m 的 default 属性上面。那么此时可能会想到一个问题,这样会不会产生冲突呢?
其实不会,因为 default 是一个关键字,所以我们不能定义一个名为 default 的具名导出。
总结
总的来说,同一个项目中出现两种模块化规范混用的情况其实是很常见的,比如:
- 导入了第三方包,第三方包的模块化规范与本项目不一致。
- 项目可能需要运行在多个环境中,又或者由团队协作开发,开发规范约束力不强。
以上是我个人的理解,主要是从导入导出的是模块的部分还是全部这个角度进行推理和组织,理由有一些牵强,但是可以勉强连贯起来。但其实我觉得还是使用 import xx from 'xx' 去导入 module.exports 会更加合理,而且也没有冲突,并且实现上也不复杂。不知道像 ts 这些工具设计使用 import * as xx from 'xx' 去导入 module.exports 的初衷是什么?