协慌网

登录 贡献 社区

Node.js 中的 module.exports 与 export

我在 Node.js 模块中找到了以下合同:

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

我不知道什么之间的不同module.exportsexports ,为什么都被用在这里。

答案

即使很久以前就已经回答并接受了这个问题,但我只想分享我的 2 美分:

您可以想象,在文件的开头有类似的内容(仅供说明):

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

在此处输入图片说明

所以,不管你做什么只是记住, module.exports和 NOT exports将从您的模块,当你需要从别的地方该模块被退回。

因此,当您执行以下操作时:

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

要添加 2 个功能ab与对象到module.exports点,所以typeof返回的结果将是一个object{ a: [Function], b: [Function] }

当然,这是同样的结果,如果你使用的是你会得到module.exports在这个例子中,而不是exports

在这种情况下,您希望您的module.exports表现得像一个导出值的容器。而如果只想导出构造函数,那么使用module.exportsexports应该有一些知识;(再次记住,在需要某些东西而不是export module.exports )。

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

因为与exports ,该参考文献没有了,其中指向对象module.exports点,所以没有之间的关系exportsmodule.exports了。在这种情况下, module.exports仍指向将返回的空对象{}

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

设置module.exports允许required时像调用函数一样调用database_module函数。简单地设置exports将不允许导出该函数,因为节点将导出对象module.exports引用。以下代码不允许用户调用该函数。

module.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 的基本上不出口的对象, exports目前的参考,但出口的是什么性质exports最初引用。尽管Node.js确实导出了对象module.exports引用,但允许您像调用函数一样调用它。


第二个最不重要的原因

他们同时设置module.exportsexports ,确保exports未引用之前导出的对象。通过同时设置两者,可以将exports用作速记,并避免以后出现潜在的错误。

使用exports.prop = true而不是module.exports.prop = true可以节省字符并避免混淆。

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 = [];
}

如您所见,每个模块对象都有一个名称为exports的属性。这最终是作为require一部分返回的。

require 的下一步是将 file1.js 的内容包装到一个匿名函数中,如下所示:

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
});

而这个匿名函数被调用下面的方式, module这里指的是Module对象之前创建。

(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 的一部分导出或返回。