我在 Node.js module中找到了以下合同:
module.exports = exports = nano = function database_module(cfg) {...}
我不知道什么是之间的差异module.exports
和exports
为什么都被用在这里。
我在 Node.js module中找到了以下合同:
module.exports = exports = nano = function database_module(cfg) {...}
我不知道什么是之间的差异module.exports
和exports
为什么都被用在这里。
尽管很久以前就已经回答并接受了问题,但我只想分享我的 2 美分:
你可以想象在你的文件的最开始有这样的东西(只是为了解释):
var module = new Module(...);
var exports = module.exports;
因此,无论您做什么,请记住,当您从其他地方需要该module时module.exports
,不会exports
从您的module返回。
因此,当您执行以下操作时:
exports.a = function() {
console.log("a");
}
exports.b = function() {
console.log("b");
}
您正在添加 2 个函数a
和b
指向的对象module.exports
,因此typeof
返回结果将是object
:{ a: [Function], b: [Function] }
当然,如果您module.exports
在本示例中使用exports
.
在这种情况下,您希望自己module.exports
的行为像一个导出值的容器。然而,如果您只想导出一个构造函数,那么您应该了解使用module.exports
or 的一些知识exports
;(再次记住,module.exports
当您需要某些东西时将返回,而不是export
)。
module.exports = function Something() {
console.log('bla bla');
}
现在typeof
返回结果是'function'
,您可以要求它并立即调用:
var x = require('./file1.js')();
因为您将返回结果覆盖为一个函数。
但是,使用exports
您不能使用以下内容:
exports = function Something() {
console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function
因为 with exports
,引用不再指向指向的对象module.exports
,所以exports
和之间module.exports
不再有关系。在这种情况下module.exports
仍然指向{}
将返回的空对象。
另一个主题的公认答案也应该有所帮助: JavaScript 是否通过引用传递?
设置module.exports
允许在database_module
时像函数一样调用函数required
。简单的设置exports
不允许导出函数,因为节点导出对象module.exports
引用。以下代码不允许用户调用该函数。
以下将不起作用。
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不会导出exports
当前引用的对象,而是导出exports
最初引用的对象的属性。尽管Node.js确实导出了对象module.exports
引用,但允许您像调用函数一样调用它。
他们同时设置module.exports
和exports
以确保exports
不引用先前导出的对象。通过将两者都设置exports
为速记,并避免以后出现潜在的错误。
使用exports.prop = true
而不是module.exports.prop = true
保存字符并避免混淆。
基本上答案在于通过require
语句需要module时实际发生的情况。假设这是第一次需要该module。
例如:
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 = [];
}
如您所见,每个module对象都有一个名为 name 的属性exports
。这是最终作为require
.
require 的下一步是将 file1.js 的内容包装成一个匿名函数,如下所示:
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
});
而这个匿名函数的调用方式如下,module
这里指的Module
是之前创建的Object。
(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
。从本质上讲,它为module程序员提供了便利。
但是,需要谨慎使用这种便利。在任何情况下,如果尝试将新对象分配给导出,请确保我们这样做。
exports = module.exports = {};
如果我们按照错误的方式来做,module.exports
仍然会指向作为module实例的一部分创建的对象。
exports = {};
因此,向上述导出对象添加任何内容都不会对 module.exports 对象产生任何影响,并且不会作为 require 的一部分导出或返回任何内容。
最初,module.exports=exports
和require
函数返回module.exports
所指的对象。
如果我们向对象添加属性,比如exports.a=1
,那么 module.exports 和exports仍然引用同一个对象。因此,如果我们调用 require 并将module分配给一个变量,那么该变量具有一个属性 a,其值为 1;
但是如果我们覆盖其中一个,例如,,exports=function(){}
那么它们现在就不同了:exports 指的是一个新对象,module.exports 指的是原始对象。如果我们需要该文件,它不会返回新对象,因为 module.exports 不是指新对象。
对我来说,我会不断添加新属性,或者将它们都覆盖到一个新对象中。只覆盖一个是不对的。请记住,这module.exports
是真正的老板。
exports
并且module.exports
是相同的,除非你重新分配exports
你的module中。
考虑它的最简单方法是认为这一行隐含在每个module的顶部。
var exports = module.exports = {};
如果在您的module内重新分配exports
,则您在module内重新分配它并且它不再等于module.exports
。这就是为什么,如果你想导出一个函数,你必须这样做:
module.exports = function() { ... }
如果您只是将您的function() { ... }
to分配给exports
,您将重新分配exports
to 不再指向module.exports
。
如果你不想module.exports
每次都引用你的函数,你可以这样做:
module.exports = exports = function() { ... }
请注意,这module.exports
是最左边的参数。
附加属性exports
是不一样的,因为你没有重新分配它。这就是为什么这有效
exports.foo = function() { ... }