node.js CommonJs 模块系统中“module.exports”和“exports”的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16383795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between "module.exports" and "exports" in the CommonJs Module System
提问by Xiao Peng - ZenUML.com
On this page (http://docs.nodejitsu.com/articles/getting-started/what-is-require), it states that "If you want to set the exports object to a function or a new object, you have to use the module.exports object."
在此页面上(http://docs.nodejitsu.com/articles/getting-started/what-is-require),它指出“如果要将导出对象设置为函数或新对象,则必须使用 module.exports 对象。”
My question is why.
我的问题是为什么。
// right
module.exports = function () {
console.log("hello world")
}
// wrong
exports = function () {
console.log("hello world")
}
I console.logged the result (result=require(example.js)) and the first one is [Function]the second one is {}.
我控制台记录了结果 ( result=require(example.js)),第一个是[Function]第二个是{}.
Could you please explain the reason behind it? I read the post here: module.exports vs exports in Node.js. It is helpful, but does not explain the reason why it is designed in that way. Will there be a problem if the reference of exports be returned directly?
你能解释一下背后的原因吗?我在这里阅读了这篇文章:module.exports 与 Node.js 中的导出。这很有帮助,但没有解释为什么这样设计的原因。直接返回exports的reference会不会有问题?
回答by goto-bus-stop
moduleis a plain JavaScript object with an exportsproperty. exportsis a plain JavaScript variable that happens to be set to module.exports.
At the end of your file, node.js will basically 'return' module.exportsto the requirefunction. A simplified way to view a JS file in Node could be this:
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;
If you set a property on exports, like exports.a = 9;, that will set module.exports.aas well because objects are passed around as references in JavaScript, which means that if you set multiple variables to the same object, they areall the same object; so then exportsand module.exportsare the same object.
But if you set exportsto something new, it will no longer be set to module.exports, so exportsand module.exportsare no longer the same object.
如果你在 上设置一个属性exports,比如exports.a = 9;,它也会设置module.exports.a,因为对象在 JavaScript 中作为引用传递,这意味着如果你为同一个对象设置多个变量,它们都是同一个对象;所以 thenexports和module.exports是同一个对象。
但是如果您设置exports为新的东西,它将不再设置为module.exports,因此exports和module.exports不再是同一个对象。
回答by Sdembla
Renee's answer is well explained. Addition to the answer with an example:
蕾妮的回答得到了很好的解释。除了一个例子的答案:
Node does a lot of things to your file and one of the important is WRAPPING your file. Inside nodejs source code "module.exports" is returned. Lets take a step back and understand the wrapper. Suppose you have
Node 对你的文件做了很多事情,其中一项重要的事情就是包装你的文件。返回内部 nodejs 源代码“module.exports”。让我们退后一步,了解包装器。假设你有
greet.js
问候.js
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
the above code is wrapped as IIFE(Immediately Invoked Function Expression) inside nodejs source code as follows:
上面的代码在 nodejs 源代码中被包装为 IIFE(立即调用函数表达式),如下所示:
(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
and the above function is invoked (.apply()) and returned module.exports. At this time module.exports and exports pointing to the same reference.
并且上面的函数被调用(.apply())并返回module.exports。这时module.exports和exports指向同一个引用。
Now, imagine you re-write greet.js as
现在,想象一下你将 greet.js 重写为
exports = function () {
console.log('Hello World');
};
console.log(exports);
console.log(module.exports);
the output will be
输出将是
[Function]
{}
the reason is : module.exports is an empty object. We did not set anything to module.exports rather we set exports = function()..... in new greet.js. So, module.exports is empty.
原因是:module.exports 是一个空对象。我们没有为 module.exports 设置任何东西,而是在新的greet.js 中设置了exports = function(.....。所以,module.exports 是空的。
Technically exports and module.exports should point to same reference(thats correct!!). But we use "=" when assigning function().... to exports, which creates another object in the memory. So, module.exports and exports produce different results. When it comes to exports we can't override it.
从技术上讲,导出和 module.exports 应该指向相同的引用(这是正确的!!)。但是我们在将 function().... 分配给导出时使用“=”,这会在内存中创建另一个对象。因此,module.exports 和exports 产生不同的结果。当涉及到导出时,我们无法覆盖它。
Now, imagine you re-write (this is called Mutation) greet.js (referring to Renee answer) as
现在,假设你重写(这称为 Mutation)greet.js(指 Renee 的回答)为
exports.a = function() {
console.log("Hello");
}
console.log(exports);
console.log(module.exports);
the output will be
输出将是
{ a: [Function] }
{ a: [Function] }
As you can see module.exports and exports are pointing to same reference which is a function. If you set a property on exports then it will be set on module.exports because in JS, objects are pass by reference.
如您所见,module.exports 和exports 指向相同的引用,这是一个函数。如果您在导出上设置属性,那么它将在 module.exports 上设置,因为在 JS 中,对象是通过引用传递的。
Conclusion is always use module.exports to avoid confusion. Hope this helps. Happy coding :)
结论是始终使用 module.exports 以避免混淆。希望这可以帮助。快乐编码:)
回答by Rodrigo Branas
Also, one things that may help to understand:
此外,一件事可能有助于理解:
math.js
数学.js
this.add = function (a, b) {
return a + b;
};
client.js
客户端.js
var math = require('./math');
console.log(math.add(2,2); // 4;
Great, in this case:
太好了,在这种情况下:
console.log(this === module.exports); // true
console.log(this === exports); // true
console.log(module.exports === exports); // true
Thus, by default, "this" is actually equals to module.exports.
因此,默认情况下,“this”实际上等于 module.exports。
However, if you change your implementation to:
但是,如果您将实现更改为:
math.js
数学.js
var add = function (a, b) {
return a + b;
};
module.exports = {
add: add
};
In this case, it will work fine, however, "this" is not equal to module.exports anymore, because a new object was created.
在这种情况下,它会正常工作,但是,“this”不再等于 module.exports,因为创建了一个新对象。
console.log(this === module.exports); // false
console.log(this === exports); // true
console.log(module.exports === exports); // false
And now, what will be returned by the require is what was defined inside the module.exports, not this or exports, anymore.
现在,require 将返回的内容是在 module.exports 中定义的内容,不再是 this 或exports。
Another way to do it would be:
另一种方法是:
math.js
数学.js
module.exports.add = function (a, b) {
return a + b;
};
Or:
或者:
math.js
数学.js
exports.add = function (a, b) {
return a + b;
};
回答by fengshuo
Rene's answer about the relationship between exportsand module.exportsis quite clear, it's all about javascript references. Just want to add that:
刘若英的约之间的关系答案exports和module.exports是相当清楚的,它是所有关于JavaScript的引用。只想补充一点:
We see this in many node modules:
我们在许多节点模块中看到了这一点:
var app = exports = module.exports = {};
var app = exports = module.exports = {};
This will make sure that even if we changed module.exports, we can still use exports by making those two variables point to the same object.
这将确保即使我们更改了 module.exports,我们仍然可以通过使这两个变量指向同一个对象来使用导出。
回答by Shashwat Gupta
myTest.js
我的测试.js
module.exports.get = function () {};
exports.put = function () {};
console.log(module.exports)
// output: { get: [Function], put: [Function] }
exportsand module.exportsare the same and a reference to the same object. You can add properties by both ways as per your convenience.
exports并且module.exports是相同的并且是对同一个对象的引用。您可以根据自己的方便通过两种方式添加属性。

