简体   繁体   English

CommonJs模块系统中“module.exports”和“exports”的区别

[英]Difference between "module.exports" and "exports" in the CommonJs Module System

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 ) 上,它声明“如果要将导出 object 设置为 function 或新的 object,则必须使用 module.exports object。”

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 .我在这里阅读了这篇文章: 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? exports的reference直接返回会不会有问题?

module is a plain JavaScript object with an exports property. module是一个带有exports属性的普通 JavaScript 对象。 exports is a plain JavaScript variable that happens to be set to module.exports . exports是一个普通的JavaScript变量,恰好被设置为module.exports At the end of your file, node.js will basically 'return' module.exports to the require function.在文件的末尾,node.js 基本上会“返回” module.exportsrequire函数。 A simplified way to view a JS file in Node could be this:在 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;如果你在exports上设置了一个属性,比如exports.a = 9; , that will set module.exports.a as well because objects are passed around as references in JavaScript, which means that if you set multiple variables to the same object, they are all the same object; , 这也将设置module.exports.a ,因为对象在 JavaScript 中作为引用传递,这意味着如果您为同一个对象设置多个变量,它们都是同一个对象; so then exports and module.exports are the same object.所以exportsmodule.exports是同一个对象。
But if you set exports to something new, it will no longer be set to module.exports , so exports and module.exports are no longer the same object.但是如果您将exports设置为新的内容,它将不再设置为module.exports ,因此exportsmodule.exports不再是同一个对象。

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. Node 对你的文件做了很多事情,其中​​一项重要的事情就是包装你的文件。 Inside nodejs source code "module.exports" is returned.返回内部 nodejs 源代码“module.exports”。 Lets take a step back and understand the wrapper.让我们退后一步,了解包装器。 Suppose you have假设你有

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.并且上面的函数被调用(.apply())并返回module.exports。 At this time module.exports and exports pointing to the same reference.这时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.原因是:module.exports 是一个空对象。 We did not set anything to module.exports rather we set exports = function()..... in new greet.js.我们没有为 module.exports 设置任何东西,而是在新的greet.js 中设置了exports = function(.....。 So, module.exports is empty.所以,module.exports 是空的。

Technically exports and module.exports should point to same reference(thats correct!!).从技术上讲,导出和 module.exports 应该指向相同的引用(这是正确的!!)。 But we use "=" when assigning function().... to exports, which creates another object in the memory.但是我们在将 function().... 分配给导出时使用“=”,这会在内存中创建另一个对象。 So, module.exports and exports produce different results.因此,module.exports 和exports 产生不同的结果。 When it comes to exports we can't override it.当涉及到导出时,我们无法覆盖它。

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.如您所见,module.exports 和exports 指向相同的引用,这是一个函数。 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 上设置,因为在 JS 中,对象是通过引用传递的。

Conclusion is always use module.exports to avoid confusion.结论是始终使用 module.exports 以避免混淆。 Hope this helps.希望这可以帮助。 Happy coding :)快乐编码:)

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;
};

Rene's answer about the relationship between exports and module.exports is quite clear, it's all about javascript references. Rene 关于exportsmodule.exports之间关系的回答很清楚,都是关于javascript 引用的。 Just want to add that:只想补充一点:

We see this in many node modules:我们在许多节点模块中看到了这一点:

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,我们仍然可以通过使这两个变量指向同一个对象来使用导出。

myTest.js我的测试.js

module.exports.get = function () {};

exports.put = function () {};

console.log(module.exports)
// output: { get: [Function], put: [Function] }

exports and module.exports are the same and a reference to the same object. exportsmodule.exports是相同的,以相同的对象的引用。 You can add properties by both ways as per your convenience.您可以根据自己的方便通过两种方式添加属性。

As all answers posted above are well explained, I want to add something which I faced today.由于上面发布的所有答案都得到了很好的解释,因此我想添加一些我今天面临的问题。

When you export something using exports then you have to use it with variable.当您使用导出导出某些内容时,您必须将其与变量一起使用。 Like,喜欢,

File1.js文件1.js

exports.a = 5;

In another file在另一个文件中

File2.js文件2.js

const A = require("./File1.js");
console.log(A.a);

and using module.exports并使用module.exports

File1.js文件1.js

module.exports.a = 5;

In File2.js在 File2.js 中

const A = require("./File1.js");
console.log(A.a);

and default module.exports默认 module.exports

File1.js文件1.js

module.exports = 5;

in File2.js在 File2.js 中

const A = require("./File2.js");
console.log(A);

node does something like this:节点做这样的事情:

module.exports = exports = {}

module.exports and exports refer to same object. module.exports 和exports 引用同一个对象。

This is done just for convenience.这样做只是为了方便。 so instead of writing something like this所以不要写这样的东西

module.exports.PI = 3.14

we can write我们可以写

exports.PI = 3.14

so it is ok to add a property to exports but assigning it to a different object is not ok所以可以将属性添加到导出,但将其分配给不同的对象是不行的

exports.add = function(){
.
.
} 

↑ this is OK and same as module.exports.add = function(){...} ↑ 这没问题,和 module.exports.add = function(){...} 一样

exports = function(){
.
.
} 

↑ this is not ok and and empty object will be returned as module.exports still refers to {} and exports refer to different object. ↑ 这不行,并且会返回空对象,因为 module.exports 仍然指的是 {},而exports 指的是不同的对象。

There are two difference between module.exports and exports module.exportsexports有两个区别

  1. When export a single class, variable or function from one module to another module, we use the module.exports .当将单个类、变量或函数从一个模块导出到另一个模块时,我们使用module.exports But export to multiple variables or functions from one module to another, we use exports .但是将多个变量或函数从一个模块导出到另一个模块,我们使用exports

  2. module.exports is the object reference that gets returned from the require() calls. module.exports是从 require() 调用返回的对象引用。 But exports is not returned by require().但是 require() 不会返回exports

see more details with examples >> link通过示例查看更多详细信息 >> 链接

You can think of exports as a shortcut to module.exports within a given module.您可以将 exports 视为给定模块中 module.exports 的快捷方式。 In fact, exports is just a variable that gets initialized to the value of module.exports before the module is evaluated.事实上,exports 只是一个变量,它在评估模块之前被初始化为 module.exports 的值。 That value is a reference to an object (empty object in this case).该值是对 object 的引用(在本例中为空 object)。 This means that exports holds a reference to the same object referenced by module.exports.这意味着 exports 持有对 module.exports 引用的相同 object 的引用。 It also means that by assigning another value to exports it's no longer bound to module.exports.这也意味着通过为 exports 分配另一个值,它不再绑定到 module.exports。

This explanation from MDN is the most clear to me. MDN的这个解释对我来说是最清楚的。

Basically, there is one object in memory which is referenced by 2 variables - exports and module.exports.基本上,memory 中有一个 object,它由 2 个变量引用 - exports 和 module.exports。

exports.a = 23

equals等于

module.exports = {a:23}

But,但,

exports = {a:23}

does not equal不相等

module.exports = {a:23}

When you assign a new object to exports variable directly, then that variable does not refer to module.exports anymore.当您直接将新的 object 分配给exports变量时,该变量不再引用module.exports

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM