Nodejs,CommonJs中的exports和module.exports的区别

使用exports和module.exports导出变量

exports 变量是在模块的文件级作用域内可用的,且在模块执行之前赋值给 module.exports。

exports.name = '前端小兵'

虽然只用了exports导出name变量,但最终的效果类似于 module.exports.name = exports.name。

我们知道js是顺序执行的,所以我们在导出变量的时候,如果遇到相同变量的话,下面的代码是会覆盖上面的相同变量赋值。

module.exports.name = '前端小兵2'
exports.name = '前端小兵'

根据上面的规则,可以知道最后导出的变量name的值是“前端小兵”。

不能直接将变量赋值exports

exports = { hello: false };  // 不导出,仅在模块中可用。

也就是上当我们使用exports直接导出值的时候,是不会将值赋给module.exports的,所以上面的代码在require的时候不会有任何变量导出。

注意书写顺序

module.exports.name = '前端小兵'
module.exports = { hello: false }
// 结果: { hello: false }

module.exports = { hello: false }
module.exports.name = '前端小兵'
// 结果: { hello: false, name: '前端小兵' }

可以看到书写顺序对于导出值的影响,module.exports 加一个变量,是会叠加到导出内容的,但对于直接将对象值赋值给module.exports的行为,是会直接覆盖之前的内容的。

require导入的模拟代码

我们来看看require在执行导入的过程中,module.exports和exports都做了哪些操作。

function require(/* ... */) {
    const module = { exports: {} };  // 也就是模块自带一个module.exports
    ((module, exports) => {
        // 模块代码在这。在这个例子中,定义了一个函数。
        function someFunc() {}
        exports = someFunc;
        // 此时,exports 不再是一个 module.exports 的快捷方式,
        // 且这个模块依然导出一个空的默认对象。
        module.exports = someFunc;
        // 此时,该模块导出 someFunc,而不是默认对象。
    })(module, module.exports);
    return module.exports;
}


关闭(Esc)