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

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

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


当前回答

设置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=导出,require函数返回module.exports引用的对象。

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

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

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

基本上,答案在于当通过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的一部分导出或返回任何内容。

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

尽管这个问题早就得到了回答和接受,但我只想分享我的2分钱:

您可以想象,在文件的开头有这样的内容(仅供解释):

var module = new Module(...);
var exports = module.exports;

因此,无论您做什么,只要记住,当您从其他地方需要模块时,模块将返回module.exports和NOT导出。

所以,当你做如下事情时:

exports.a = function() {
    console.log("a");
}
exports.b = function() {
    console.log("b");
}

您正在向module.exports指向的对象添加2个函数a和b,因此返回结果的类型将是一个对象:{a:[Function],b:[Function〕}

当然,如果在本例中使用module.exports而不是exports,则会得到相同的结果。

在这种情况下,您希望module.exports的行为类似于导出值的容器。然而,如果您只想导出构造函数,那么对于使用module.exports或exports,您应该知道一些事情;(请再次记住,当您需要某些东西时,会返回module.exports,而不是export)。

module.exports = function Something() {
    console.log('bla bla');
}

现在返回结果的类型是“function”,您可以要求它并立即调用,如:var x=require('./file1.js')();因为您将返回结果覆盖为函数。

但是,使用导出时不能使用以下内容:

exports = function Something() {
    console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function

因为对于导出,引用不再指向module.exports所指向的对象,因此导出和module.export之间不再存在关系。在这种情况下,module.exports仍然指向将返回的空对象{}。

另一个主题的公认答案也应有助于:JavaScript是否通过引用传递?

我通过了一些测试,我认为这可能会对这个问题有所启发。。。

应用.js:

var ...
  , routes = require('./routes')
  ...;
...
console.log('@routes', routes);
...

/routes/index.js的版本:

exports = function fn(){}; // outputs "@routes {}"

exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

module.exports = function fn(){};  // outputs "@routes function fn(){}"

module.exports.fn = function fn(){};  // outputs "@routes { fn: [Function: fn] }"

我甚至添加了新文件:

./routes/index.js:

module.exports = require('./not-index.js');
module.exports = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

我们得到输出“@routes{}”


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports = function fn(){};

./routes/user.js:

exports = function user(){};

我们得到输出“@routes{fn:{},user:{}}”


./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.user = function user(){};

我们得到输出“@routes{user:[Function:user]}”如果我们将user.js更改为{ThisLoadedLast:[Function:ThisLoadedLast]},我们将得到输出“@routes{ThisLoadedLast:[Function:TThisLoadedlast]}”。


但如果我们修改/routes/index.js。。。

./routes/index.js:

module.exports.fn = require('./not-index.js');
module.exports.ThisLoadedLast = require('./user.js');

./routes/not-index.js:

exports.fn = function fn(){};

./routes/user.js:

exports.ThisLoadedLast = function ThisLoadedLast(){};

…我们得到“@routes{fn:{fn:[Function:fn]},ThisLoadedLast:{ThisLoadedLast:[Function:ThisLoadedLast]}}”

所以我建议在模块定义中始终使用module.exports。

我不完全理解Node内部的情况,但如果您能理解这一点,请发表评论,因为我相信这会有所帮助。

--快乐的编码