exports和require怎么来的?
错误答案: 全局变量
- window不是Node中的全局对象
- Node中有一个全局对象global, 作用和window类似
正确答案: 函数参数
- 函数的标识: arguments
获取函数的所有实参 - 获取函数自身 arguments.callee
返回函数本身
node文件组成剖析
当node在执行模块中的代码时,它会首先在代码的最顶部,添加如下代码
function (exports, require, module, __filename, __dirname) {
在代码的最底部,添加
}
即将一个JS文件代码以函数的形式包裹起来
所以模块中的代码都是包装在一个函数中执行的,并且在函数执行的同时传递进了5个实参
- exports: 该对象用来将函数内部的局部变量或局部函数暴露到外部
- require: 用来引入外部的模块
- module: 代表的是当前模块本身, exports就是module的属性; 我们既可以使用 exports 导出,也可以使用module.exports导出
- __filename: 当前模块的完整路径
- __dirname: 当前模块所在文件夹的完整路径
结论:
- 在Node.js中,都是以模块化思想进行开发,一个JS文件就可以看做一个模块。
- 在模块中,可以使用export向外暴露,也可以通过require进行引入。
- 一个模块就是一个函数,而require和exports都是其中的参数
在每一个模块中,最终返回的是module.exports.
exports类似一根指针,指向module.exports。因此,exports只能通过点语法获取并向外输出,无法通过赋值对象输出。
(function (exports, require, module, __filename, __dirname) {
exports = module.exports = {};
// 赋值操作
return module.exports;
})()
所以module改变方式是不受影响的,但exports改变就无法正确返回。
exports 和 module.exports的区别
-
如果输出
exports===module.exports
是正确的 -
在单个暴露的时候
通过exports暴露后引入正常输出
通过module.exports也可以正常输出 -
显然,一个个向外暴露太过繁琐,可以一起暴露
此时,通过module.exports向外暴露是正常的
但是单纯的使用exports却不可以
原因:在每一个模块中,最终返回的是module.exports.
因为在模块中,exports是指向module exports的,所以exports的地址和module.exports的地址相同。
- 如果module.exports使用对象输出(对象是地址引用!)
因为exports指向module.exports,所以当module.exports指向模块对象0x002的时候,exports也就自动指向了0x002
- 而如果将对象绑定在exports上,则只改变了exports的地址,并不会改变module.exports的地址,而向外暴露的正式module.exports,所以单纯的使用exports绑定对象是无法实现的
结论
1. exports只能使用.语法来向外暴露内部变量
exports.xxx = xxx;
2. module.exports既可以通过.语法,也可以直接赋值一个对象
module.exports.xxx = yyy;
module.exports = {xxx: yyy};