module.exports与 exports, export和 export default, import 及 require 的关系

0x01 先说两种加载方式 CommonJS 和 AMD

  1. CommonJS 用于服务端,即 nodeJs 加载模块的方式。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。模块之间通过 require 进行加载。
  2. AMD 加载方式用于浏览器环境中,因为浏览器从网络加载 JS 有延迟,无法像 nodeJs 服务器环境一样直接读文件。所以使用 define('moduleName',['dependences'], function(){}) 这种方式定义模块。

关于两种方式的介绍,可以看阮一峰的文章: JS 模块化:AMD 规范

0x02 基础知识

一个基础的知识是:module.exportsexportsrequire 这三个是 CommonJS 模块规范。

exportexport defaultimport 属于 ES6 规范。

在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

具体介绍继续看阮一峰老师的 ES6教程

从模块导出和导入来分:

导出模块:module.exportsexportsexportexport default

导入模块:requireimport

0x03 module.exports 和 exports 的关系

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// file: calculate.js
let x = 5
let add = function(value) {
return x + value
}
//使用 module.exports 输出变量
module.exports.x = x
//使用 exports 输出方法
exports.add = add
//file: index.js
let calculate = require('./calculate.js')
console.log(calculate.x) //输出 5
console.log(calculate.add(1)) //输出 6

其实 exports变量指向 module.exports,即相当于在每个文件头部有这么一段代码

1
let exports = module.exports

所以我们可以直接在 exports 对象上添加方法,表示对外输出接口。等同于在 module.exports 上添加方法。

需要注意的是,不能直接将 exports 变量指向一个值,因为这样等于切断了exportsmodule.exports的联系。

0x04 export 和 export default 的关系

两者的区别主要在于 export 导出的是一组方法或者变量。 export default 只导出一个方法或变量。

举个栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//calculate.js
let x = function
let y = function
let z = function
export {x, y, z}
//这时候可以使用 import 直接导入这三个方法
import {x, y, z} from './calculate'
//如果使用 export default
export default {x, y, z}
//那么 import 就只能导入一个变量
import Calculate from './calculate'
//然后再执行
Calculate.x
Calculate.y
//使用了 export {x, y, z}, 也想 import 为一个变量怎么办?
//可以这样
import * as Calculate from './calculate'

之前迷惑是没有区分开 CommonJS 和 ES6 模块加载之间的关系,原来的替换关系。