在CommonJS
模块规范中,通过require
来引入外部模块,通过exports
和module.exports
来导出模块
-
使用
require
引入模块时,会得到模块导出的内容,可以用一个变量接收他 -
比如有两个文件
import.js
和export.js
,现在要在import.js
中引入export.js
-
export.js
console.log('我是export.js'); exports.hello = 'world'; module.exports.year = '2021'; setTimeout(() => { console.log(exports); },2000); console.log(exports === module.exports);
-
在
import.js
中引入export.js
console.log('我是import.js'); //require('./export'); const lib = require('./export'); console.log('我是export.js导出的内容:', lib); // 给lib添加属性 lib.additional = 'test';
-
在控制台执行
node import.js
可以得到
-
-
在node官方文档中有提到,在执行模块代码之前,Node.js 会用下面的函数包装器对其进行包装
(function(exports,require,module,__filename,__dirname){ ... })
- 这样有助于将*变量(用
var
,const
或定义let
)保持在模块而不是全局对象的范围内。 - 有助于提供一些实际特定于模块的全局变量,例如:
- 实现者可以用
module
和exports
对象实现模块值的导出。 - 便利变量
__filename
和__dirname
,包含模块的绝对文件名和目录路径。
- 实现者可以用
- 这样有助于将*变量(用
-
从上面可以看出
exports
和module
是一个模块特有的全局变量,并且module
也有一个exports
属性,使用这个属性可以实现和exports
一样的功能
exports
和module.exports
的区别
-
在执行
console.log(exports === module.exports);
的时候,得到的结果为true
-
说明
exports
和module.exports
是相同的,指向同一个内存地址 -
注意,这个时候执行
console.log('我是export.js导出的内容:', lib);
到的内容还是{ hello: 'world', year: '2021' }
- 导出的内容包含了
exports.hello
和module.exports.year
- 导出的内容包含了
-
这时候,改变一下
module.exports
导出的内容,其他的不变module.exports = { year: '2021' };
-
打印一下得到
- 这会
console.log(exports === module.exports);
的结果为false
,exports
和module.exports
不相等了 - 执行
console.log('我是export.js导出的内容:', lib);
,得到的导出内容也只有module.exports
导出的了 - 定时器里打印的
exports
也只有exports.hello
导出的内容了
- 这会
-
当改变
module.exports
导出的内容为一个对象后,让module.exports
指向了新的内存地址,使得他俩不再相等 -
执行
import.js
得到的export.js
导出的内容只有year:2021
也说明,只有module.exports
的变量被返回了,前面导出的内容还有hello:world
是因为之前他们是指向同一个内存地址的 -
module.exports
指向了新的内存地址后,在改变一下定时器打印的内容为console.log(module.exports)
-
执行
import.js
可以得到 -
跟上面的打印结果作对比可以发现,在
import.js
中给lib
添加的新属性添加到module.exports
身上了 -
在做一个实验,假设
module.exports
和exports
还是指向同一个内存地址,有如下代码console.log('我是export.js'); exports.hello = 'world'; module.exports.year = '2020'; exports.year = '2022'; setTimeout(() => { console.log(exports); },2000); console.log(exports === module.exports);
- 执行
import.js
可以得到
- 会发现
module.exports.year
的值被exports
改变了
- 执行
结论
-
exports
对象是module
对象的一个属性,在初始时module.exports
和exports
指向同一块内存区域 - 模块导出的是
module.exports
,exports
只是对它的引用,在不改变exports
内存的情况下,修改exports
的值可以改变module.exports
的值 - 导出时尽量使用
module.exports
,以免因为各种赋值导致的混乱