我在Node.js模块中找到了以下契约:

module.exports = exports = nano = function database_module(cfg) {...}

我想知道module.exports和exports之间有什么区别,为什么在这里使用它们。


当前回答

要了解这些差异,您必须首先了解Node.js在运行时对每个模块做了什么。Node.js为每个模块创建一个包装函数:

 (function(exports, require, module, __filename, __dirname) {

 })()

注意,第一个param导出是一个空对象,第三个param模块是一个具有许多财产的对象,其中一个财产名为exports。这是导出的来源和module.exports的来源。前者是变量对象,后者是模块对象的属性。

在模块中,Node.js在开始时自动执行以下操作:module.exports=exports,并最终返回module.exports。

因此,您可以看到,如果您为导出重新分配一些值,那么它不会对module.exports产生任何影响

let exports = {};
const module = {};
module.exports = exports;

exports = { a: 1 }
console.log(module.exports) // {}

但是如果你更新导出的财产,它肯定会对module.exports产生影响。因为它们都指向同一个对象。

let exports = {};
const module = {};
module.exports = exports;

exports.a = 1;
module.exports.b = 2;
console.log(module.exports) // { a: 1, b: 2 }

还要注意,如果您将另一个值重新分配给module.exports,那么对于导出更新来说似乎没有意义。由于module.exports指向另一个对象,因此忽略导出上的每个更新。

let exports = {};
const module = {};
module.exports = exports;

exports.a = 1;
module.exports = {
  hello: () => console.log('hello')
}
console.log(module.exports) // { hello: () => console.log('hello')}

其他回答

我只是做了一些测试,结果发现,在nodejs的模块代码中,应该是这样的:

var module.exports = {};
var exports = module.exports;

so:

1:

exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.

2:

exports.abc = function(){}; // works!
exports.efg = function(){}; // works!

3:但是,在这种情况下

module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = 'value a'; // works
exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)

以下是

console.log("module:");
console.log(module);

console.log("exports:");
console.log(exports);

console.log("module.exports:");
console.log(module.exports);

也:

if(module.exports === exports){
    console.log("YES");
}else{
    console.log("NO");
}

//YES

注:CommonJS规范只允许使用exports变量来公开公共成员。因此,命名的导出模式是唯一真正与CommonJS规范兼容的模式。module.exports的使用是Node.js提供的扩展,以支持更广泛的模块定义模式。

最初,module.exports=导出,require函数返回module.exports引用的对象。

如果我们向对象添加属性,比如exports.a=1,那么module.exports和exports仍然引用同一个对象。因此,如果我们调用require并将模块分配给变量,那么该变量具有属性a,其值为1;

但是如果我们重写其中一个,例如exports=function(){},那么它们现在就不同了:exports引用新对象,module.exports引用原始对象。如果我们需要该文件,它将不会返回新对象,因为module.exports不引用新对象。

对我来说,我将继续添加新属性,或者将它们都覆盖到新对象中。只是忽略一个是不正确的。请记住,module.exports才是真正的老板。

module.export和exports都指向同一个对象,然后对模块求值。

使用require语句在另一个模块中使用模块时,添加到module.exports对象的任何属性都将可用。导出是一种快捷方式,可用于相同的事情。例如:

module.exports.add = (a, b) => a+b

相当于写:

exports.add = (a, b) => a+b

因此,只要不为导出变量分配新值,就可以了。当你这样做时:

exports = (a, b) => a+b 

当您为导出分配新值时,它不再引用导出的对象,因此将保持模块的本地状态。

如果您计划为module.exports分配一个新值,而不是向可用的初始对象添加新的财产,您可能应该考虑如下所示:

module.exports = exports = (a, b) => a+b

Node.js网站对此有很好的解释。

这是曼宁出版的动作书中关于node.js中节点模块的一个很好的描述。最终在应用程序中导出的是module.exports.exportsup简单地作为module.exports的全局引用,它最初定义为可以向其中添加财产的空对象。所以exports.myFunc只是一种速记对于module.exports.myFunc。因此,如果将导出设置为其他值,则会断开引用模块导出和导出。因为module.exports是真正的导出,导出将不再按预期工作,它不引用模块.不再导出。如果要维护该链接,可以创建module.exports再次引用导出如下:

module.exports = exports = db;