#yyds干货盘点#JavaScript 的几种模块系统

时间:2022-12-07 11:58:21

​模块系统是什么?简单来说,其实就是我们在一个文件里写代码,声明一些可以导出的字段,然后另一个文件可以将其导入并使用。

模块化的优点:

  1. 文件里声明的变量会被隔离,不会暴露到全局,可以有效解决以往变量污染全局空间的问题;
  2. 更容易看出代码之间的依赖关系,看文件头的的导入代码就知道;
  3. 方便多人协作,各自开发自己的模块,而不冲突;
  4. 不用担心文件引入的顺序;
  5. 方便以文件为单位做单元测试;

模块化解决了变量污染、代码维护、依赖顺序问题。


CommonJS

CommonJS,或者叫 CJS,是 nodejs 选择的模块化标准。

导出模块的写法:

// 集中一起导出
module.exports = {
userName: '前端西瓜哥',
// ...
}

// 或分散导出
module.exports.userName = '前端西瓜哥';

// 或
exports.userName = '前端西瓜哥';
复制代码

每个文件都可以访问到一个 module 对象,其下的 exports 属性是一个空对象,你可以给它加上属性,module.exports 将作为可以导出的代码部分。

exports 是一个别名,它指向 module.exports,用它能够少打一点字。

然后是导入模块的写法:

const Setting = require('./user');

// 或用解构写法,直接提取属性
const { userName } = require('./user');

// 或不使用任何导出内容,但希望指定对应模块文件的副作用(如给全局注入变量)
require('./user');
复制代码

require 方法能够找到对应模块文件,提取出它的 module.exports 对象,引入到当前模块中。关于 require 怎么找到模块的过程,也是一篇长篇大论,有机会另开一篇文章再讲解了。

nodejs 现在最新版也支持用 ES Modules 的方式了,需要在 package.json 上加上  ​​"type": "module"​​。

ES Modules

ES Modules,或者叫 ESM,是 ES6 引入的新特性,是模块系统的真正标准。

在 script 标签下设置 type="module",可以开启模块化加载。

当然实际上生产环境我们是不会这么做的,只是用 ES Modules 写代码,然后打包,用传统的模式运行。

导出模块的写法:

// 集中一起导出
export {
userName: '前端西瓜哥',
// ...
}

// 或分散指定
export const userName = '前端西瓜哥';

// 一种特殊的导出:默认指定
export default user;
复制代码

ES Modules 中,export 不是一个对象,准确来说都不是变量,而是新引入的关键字,用于指定要导出的变量。

然后是导入模块的写法:

// 导入需要的变量
import { userName } from './user.js';

// 导入 export default 对应的变量,这时候不需要花括号
import user from './user.js';

// 在命名冲突时,可以给导入的变量换个名字
import user as otherUser from './user.js';

// 将 export 组装成对象,包括 export default,对应 default 属性名
import * as obj from './user.js'

复制代码

根据标准,导入的模块名是要提供 ​​.js​​ 后缀名的,因为实际上的 ES Module 是会请求一个 url 的,url 必须精准。

不过我们通常会使用打包工具,可以配置一下将其省略。比如 webpack,我们可以设置 resolve.extensions 配置项来设置后缀不存在时,拼上什么后缀去查找。

AMD和CMD都是过时内容,这篇文章这里就不讲了。