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

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

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


当前回答

1.导出->用作单例实用程序2.模块导出->用作逻辑对象,如服务、模型等

其他回答

“如果您希望模块导出的根是一个函数(例如构造函数),或者如果您希望在一个赋值中导出一个完整的对象,而不是一次生成一个属性,请将其分配给module.exports而不是导出。”-http://nodejs.org/api/modules.html

在节点js中,module.js文件用于运行module.load系统。每当节点执行文件时,它都会将js文件内容包装如下

'(function (exports, require, module, __filename, __dirname) {',+
     //your js file content
 '\n});'

由于这种包装在urjs源代码中,您可以访问导出、require、模块等。。之所以使用这种方法,是因为没有其他方法可以将js文件中的功能写入另一个文件。

然后节点使用c++执行这个包装函数。此时,传递到此函数的exports对象将被填充。

您可以在这个函数中看到参数导出和模块。实际上,exports是模块构造函数函数的公共成员。

查看以下代码

将此代码复制到b.js中

console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log('----------------------------------------------');
var foo = require('a.js');
console.log("object.keys of foo: "+Object.keys(foo));
console.log('name is '+ foo);
foo();

将此代码复制到.js

exports.name = 'hello';
module.exports.name = 'hi';
module.exports.age = 23;
module.exports = function(){console.log('function to module exports')};
//exports = function(){console.log('function to export');}

现在使用节点运行

这是输出

module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true

导出为[对象对象]

foo的object.keys:名称是函数(){console.log('模块导出函数')}功能到模块导出

现在删除.js中的注释行,并注释该行上方的行然后删除b.js的最后一行并运行。

在javascript世界中,不能重新分配作为参数传递的对象,但当该函数的对象设置为另一个函数的参数时,可以更改该函数的公共成员

请记住

仅当您想在使用require关键字时获取函数时,才使用module.exports。在上面的例子中,我们varfoo=require(a.js);你可以看到我们可以将foo作为函数调用;

节点文档就是这样解释的导出对象是由Module系统创建的。有时这是不可接受的,许多人希望自己的模块是某个类的实例。为此,请将所需的导出对象分配给Module.exports

module.exports和exports都指向同一个函数database_module(cfg){…}。1|变量a,b;2|a=b=function(){console.log(“旧”);};3|b=函数(){console.log(“New”);};4|5|a();//“旧”6|b();//“新建”您可以将第3行的b更改为a,输出是相反的。结论是:a和b是独立的。因此module.exports=exports=nano=function database_module(cfg){…}相当于:var f=函数database_module(cfg){…};模块导出=f;出口=f;假设上面是foo.js所需要的module.js。module.exports=exports=nano=function database_module(cfg){…}的好处现在很清楚了:在foo.js中,由于module.exports是必需的('./module.js'):var output=require('./modules.js')();在moduls.js中:可以使用exports代替module.exports。

因此,如果exports和module.exports都指向同一个对象,您会很高兴。

您创建的每个文件都是一个模块。模块是一个对象。它具有名为exports:{}的属性,默认情况下该属性为空对象。

您可以创建函数/中间件并将其添加到这个空的导出对象中,例如exports.findById()=>{…},然后在应用程序中的任何位置使用。。。

控制器/user.js

exports.findById = () => {
    //  do something
}

需要在routes.js中使用:

const {findyId} = './controllers/user'

要了解这些差异,您必须首先了解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')}