我在Node.js模块中找到了以下契约:
module.exports = exports = nano = function database_module(cfg) {...}
我想知道module.exports和exports之间有什么区别,为什么在这里使用它们。
我在Node.js模块中找到了以下契约:
module.exports = exports = nano = function database_module(cfg) {...}
我想知道module.exports和exports之间有什么区别,为什么在这里使用它们。
当前回答
以下是
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提供的扩展,以支持更广泛的模块定义模式。
其他回答
基本上,答案在于当通过require语句需要模块时会发生什么。假设这是第一次需要模块。
例如:
var x = require('file1.js');
file1.js的内容:
module.exports = '123';
执行上述语句时,将创建Module对象。其构造函数函数为:
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
正如您所看到的,每个模块对象都有一个带有名称导出的属性。这是最终作为需求的一部分返回的内容。
require的下一步是将file1.js的内容包装成一个匿名函数,如下所示:
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
});
这个匿名函数的调用方式如下,这里的模块引用前面创建的模块对象。
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");
正如我们在函数内部看到的那样,exports的形式参数指的是module.exports。本质上,这是为模块程序员提供的便利。
然而,这种便利需要谨慎使用。在任何情况下,如果尝试将新对象分配给导出,请确保这样做。
exports = module.exports = {};
如果我们按照错误的方式执行,module.exports将仍然指向作为模块实例一部分创建的对象。
exports = {};
因此,向上面的导出对象添加任何内容都不会对module.exports对象产生任何影响,也不会作为require的一部分导出或返回任何内容。
要了解这些差异,您必须首先了解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')}
设置module.exports允许在需要时像调用函数一样调用database_module函数。简单地设置导出不允许函数导出,因为node导出对象模块。导出引用。以下代码不允许用户调用函数。
模块.js
以下操作不起作用。
exports = nano = function database_module(cfg) {return;}
如果设置了module.exports,则以下操作将起作用。
module.exports = exports = nano = function database_module(cfg) {return;}
安慰
var func = require('./module.js');
// the following line will **work** with module.exports
func();
基本上,node.js不导出导出当前引用的对象,而是导出导出最初引用的对象的财产。虽然Node.js确实导出了对象module.exports引用,但允许您像函数一样调用它。
第二个最不重要的原因
他们设置了module.exports和exports,以确保导出不引用先前导出的对象。通过设置这两个选项,您可以使用导出作为速记,并避免以后可能出现的错误。
使用exports.rop=true而不是module.exports.rop=true可以保存字符并避免混淆。
为什么这两个都用在这里
我相信他们只是想清楚module.exports、exports和nano指向同一个函数——允许您使用任意一个变量来调用文件中的函数。nano为函数的功能提供了一些上下文。
导出不会被导出(只有module.exports会被导出),那么为什么还要麻烦覆盖它呢?
冗长的权衡限制了未来错误的风险,例如在文件中使用导出而不是module.exports。它还澄清了module.exports和exports实际上指向相同的值。
module.exports与导出
只要不重新分配module.exports或exports(而是向它们都引用的对象添加值),就不会有任何问题,并且可以安全地使用exports以更简洁。
当将其中一个分配给非对象时,它们现在指向不同的位置,这可能会令人困惑,除非您有意希望module.exports是特定的(例如函数)。
将导出设置为非对象没有多大意义,因为必须在末尾设置module.exports=导出,才能在其他文件中使用它。
let module = { exports: {} };
let exports = module.exports;
exports.msg = 'hi';
console.log(module.exports === exports); // true
exports = 'yo';
console.log(module.exports === exports); // false
exports = module.exports;
console.log(module.exports === exports); // true
module.exports = 'hello';
console.log(module.exports === exports); // false
module.exports = exports;
console.log(module.exports === exports); // true
为什么将module.exports分配给函数?
更简洁!比较第二个示例的长度:
helloWorld1.js:module.exports.hello = () => console.log('hello world');
app1.js:let sayHello=require('./helloWorld1');sayHellohello;//你好,世界
helloWorld2.js:module.exports = () => console.log('hello world');
app2.js:let sayHello=require('./helloWorld2');说你好;//你好,世界
“如果您希望模块导出的根是一个函数(例如构造函数),或者如果您希望在一个赋值中导出一个完整的对象,而不是一次生成一个属性,请将其分配给module.exports而不是导出。”-http://nodejs.org/api/modules.html