在此页面 (http://docs.nodejitsu.com/articles/getting-started/what-is-require) 上,它声明“如果要将导出对象设置为函数或新对象,则必须使用 module.exports 对象。”
我的问题是为什么。
// right
module.exports = function () {
console.log("hello world")
}
// wrong
exports = function () {
console.log("hello world")
}
我控制台记录了结果 (result=require(example.js)
),第一个是 [Function]
,第二个是 {}
。
你能解释一下背后的原因吗?我在这里阅读了这篇文章:module.exports vs exports in Node.js。它很有帮助,但没有解释为什么以这种方式设计的原因。如果直接返回exports的reference会不会有问题?
module.exports
。
exports
,例如 github.com/tj/consolidate.js/blob/master/lib/consolidate.js?
module.exports
,您永远不会出错,但如果您不替换默认导出对象,则可以使用 exports
,也就是说,如果您只是附加如下属性:var foo = require('foo').foo
。此 foo
属性可以像这样导出:exports.foo = ...
,当然也可以使用 module.exports
。这是个人选择,但我目前正在适当地使用 module.exports
和 exports
。
module
是具有 exports
属性的纯 JavaScript 对象。 exports
是一个纯 JavaScript 变量,恰好设置为 module.exports
。在文件的末尾,node.js 基本上会“返回”module.exports
到 require
函数。在 Node 中查看 JS 文件的一种简化方法是:
var module = { exports: {} };
var exports = module.exports;
// your code
return module.exports;
如果您在 exports
上设置一个属性,例如 exports.a = 9;
,那么它也将设置 module.exports.a
,因为对象在 JavaScript 中作为引用传递,这意味着如果您将多个变量设置为同一个对象,它们 都是同一个对象;那么 exports
和 module.exports
是同一个对象。
但是如果您将 exports
设置为新的东西,它将不再设置为 module.exports
,因此 exports
和 module.exports
不再同一个对象。
蕾妮的回答很好解释。除了一个例子的答案:
Node 对你的文件做了很多事情,其中一个重要的事情就是包装你的文件。返回内部 nodejs 源代码“module.exports”。让我们退后一步,了解包装器。假设你有
问候.js
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
上面的代码在 nodejs 源代码中被包装为 IIFE(Immediately Invoked Function Expression),如下所示:
(function (exports, require, module, __filename, __dirname) { //add by node
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
}).apply(); //add by node
return module.exports; //add by node
上面的函数被调用 (.apply()) 并返回 module.exports。此时module.exports和exports指向同一个引用。
现在,假设您将 greet.js 重写为
exports = function () {
console.log('Hello World');
};
console.log(exports);
console.log(module.exports);
输出将是
[Function]
{}
原因是:module.exports 是一个空对象。我们没有为 module.exports 设置任何东西,而是在新的 greet.js 中设置了exports = function().....。所以,module.exports 是空的。
从技术上讲,exports 和 module.exports 应该指向相同的引用(这是正确的!!)。但是我们在将 function().... 分配给导出时使用“=”,这会在内存中创建另一个对象。因此, module.exports 和 exports 产生不同的结果。当涉及到导出时,我们不能覆盖它。
现在,假设你重写(这称为 Mutation)greet.js(指 Renee 答案)为
exports.a = function() {
console.log("Hello");
}
console.log(exports);
console.log(module.exports);
输出将是
{ a: [Function] }
{ a: [Function] }
如您所见, module.exports 和 exports 指向同一个引用,这是一个函数。如果您在导出上设置一个属性,那么它将在 module.exports 上设置,因为在 JS 中,对象是通过引用传递的。
结论总是使用 module.exports 来避免混淆。希望这可以帮助。快乐编码:)
另外,可能有助于理解的一件事:
数学.js
this.add = function (a, b) {
return a + b;
};
客户端.js
var math = require('./math');
console.log(math.add(2,2); // 4;
太好了,在这种情况下:
console.log(this === module.exports); // true
console.log(this === exports); // true
console.log(module.exports === exports); // true
因此,默认情况下,“this”实际上等于 module.exports。
但是,如果您将实现更改为:
数学.js
var add = function (a, b) {
return a + b;
};
module.exports = {
add: add
};
在这种情况下,它可以正常工作,但是,“this”不再等于 module.exports,因为创建了一个新对象。
console.log(this === module.exports); // false
console.log(this === exports); // true
console.log(module.exports === exports); // false
现在,require 将返回的是在 module.exports 中定义的内容,而不是 this 或 exports。
另一种方法是:
数学.js
module.exports.add = function (a, b) {
return a + b;
};
或者:
数学.js
exports.add = function (a, b) {
return a + b;
};
Rene 关于 exports
和 module.exports
之间关系的回答非常清楚,这完全是关于 javascript 引用。只想补充一点:
我们在许多节点模块中看到了这一点:
var app = exports = module.exports = {};
这将确保即使我们更改了 module.exports,我们仍然可以通过使这两个变量指向同一个对象来使用导出。
module.exports
和 exports
只是单独的变量,初始化为引用同一个对象。如果您更改一个变量引用的内容,这两个变量将不再引用同一事物。上面的代码行确保两个变量都初始化为同一个新对象。
节点做这样的事情:
module.exports = exports = {}
module.exports 和exports 指的是同一个对象。
这样做只是为了方便。所以不要写这样的东西
module.exports.PI = 3.14
我们可以写
exports.PI = 3.14
因此可以将属性添加到导出但将其分配给不同的对象是不行的
exports.add = function(){
.
.
}
↑ 这没关系,与 module.exports.add = function(){...} 相同
exports = function(){
.
.
}
↑ 这不行,并且空对象将作为模块返回。exports 仍然引用 {},exports 引用不同的对象。
module.exports
和 exports
之间有两个区别
当将单个类、变量或函数从一个模块导出到另一个模块时,我们使用 module.exports。但是从一个模块导出到多个变量或函数到另一个,我们使用导出。 module.exports 是从 require() 调用返回的对象引用。但是 require() 不会返回导出。
通过示例查看更多详细信息>> link
由于上面发布的所有答案都得到了很好的解释,我想添加一些我今天遇到的问题。
当您使用导出导出某些内容时,您必须将其与变量一起使用。喜欢,
文件1.js
exports.a = 5;
在另一个文件中
文件2.js
const A = require("./File1.js");
console.log(A.a);
并使用 module.exports
文件1.js
module.exports.a = 5;
在 File2.js 中
const A = require("./File1.js");
console.log(A.a);
和默认 module.exports
文件1.js
module.exports = 5;
在 File2.js 中
const A = require("./File2.js");
console.log(A);
myTest.js
module.exports.get = function () {};
exports.put = function () {};
console.log(module.exports)
// output: { get: [Function], put: [Function] }
exports
和 module.exports
是相同的并且是对同一个对象的引用。您可以根据自己的方便通过两种方式添加属性。
您可以将导出视为给定模块中 module.exports 的快捷方式。实际上,exports 只是一个变量,它在模块被评估之前被初始化为 module.exports 的值。该值是对对象的引用(在本例中为空对象)。这意味着 export 持有对 module.exports 引用的同一对象的引用。这也意味着通过为导出分配另一个值,它不再绑定到 module.exports。
MDN的这个解释对我来说是最清楚的。
基本上,内存中有一个对象被 2 个变量引用——exports 和 module.exports。
exports.a = 23
等于
module.exports = {a:23}
但,
exports = {a:23}
不等于
module.exports = {a:23}
当您直接将新对象分配给 exports
变量时,该变量不再引用 module.exports
。
不定期副业成功案例分享
module.exports
的文档也对其进行了描述:nodejs.org/api/modules.html#modules_module_exportsexports
和module.exports
?为了简单起见(和 KISS 原则),我们不能只接受(即)后者吗?exports
,它只是一个方便的速记。但是现在它永远不能被删除,因为它会破坏所有现有的代码。