在这个页面(http://docs.nodejitsu.com/articles/getting-started/what-is-require)上,它声明“如果你想将exports对象设置为一个函数或一个新对象,你必须使用模块。出口对象。”

我的问题是为什么。

// right
module.exports = function () {
  console.log("hello world")
}
// wrong
exports = function () {
  console.log("hello world")
}

我的控制台。记录结果(result=require(example.js)),第一个是[Function],第二个是{}。

你能解释一下背后的原因吗?我读了这篇文章:模块。出口vs Node.js中的出口。它是有帮助的,但并没有解释为什么它是这样设计的。如果直接退回出口的参考资料会有问题吗?


当前回答

蕾妮的答案解释得很好。用一个例子补充回答:

Node对你的文件做了很多事情,其中一个重要的是包装你的文件。在nodejs源代码"模块。Exports返回。让我们回过头来了解一下包装器。假设你有

greet.js

var greet = function () {
   console.log('Hello World');
};

module.exports = greet;

上述代码在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

上面的函数被调用(.apply())并返回module.exports。 此时模块。导出和导出指向同一个引用。

现在,想象你重写 greet.js作为

exports = function () {
   console.log('Hello World');
};
console.log(exports);
console.log(module.exports);

输出将是

[Function]
{}

原因是:模块。Exports是一个空对象。我们没有将任何东西设置为模块。我们设置Exports = function().....在new greet.js中。因此,模块。出口是空的。

技术上导出和模块。出口应该指向相同的参考(这是正确的!!)但是我们在赋值function()....时使用“=”到导出,这将在内存中创建另一个对象。因此,模块。输出和输出产生不同的结果。当涉及到输出时,我们无法覆盖它。

现在,想象你重写(这叫做突变) greet.js(指Renee answer)为

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

console.log(exports);
console.log(module.exports);

输出将是

{ a: [Function] }
{ a: [Function] }

正如你所看到的模块。Exports和Exports指向同一个引用,这是一个函数。如果你在导出上设置了一个属性,那么它将在模块上设置。因为在JS中,对象是通过引用传递的。

结论是始终使用模块。导出以避免混淆。 希望这能有所帮助。快乐编码:)

其他回答

Node是这样做的:

module.exports = exports = {}

模块。Exports和Exports引用同一个对象。

这样做只是为了方便。 所以不像这样写

module.exports.PI = 3.14

我们可以写

exports.PI = 3.14

因此,向exports添加属性是可以的,但将其分配给不同的对象是不可以的

exports.add = function(){
.
.
} 

这是可以的,和module.exports.add = function(){…}一样

exports = function(){
.
.
} 

这是不正确的,并且空对象将作为模块返回。Exports仍然引用{},Exports引用不同的对象。

蕾妮的答案解释得很好。用一个例子补充回答:

Node对你的文件做了很多事情,其中一个重要的是包装你的文件。在nodejs源代码"模块。Exports返回。让我们回过头来了解一下包装器。假设你有

greet.js

var greet = function () {
   console.log('Hello World');
};

module.exports = greet;

上述代码在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

上面的函数被调用(.apply())并返回module.exports。 此时模块。导出和导出指向同一个引用。

现在,想象你重写 greet.js作为

exports = function () {
   console.log('Hello World');
};
console.log(exports);
console.log(module.exports);

输出将是

[Function]
{}

原因是:模块。Exports是一个空对象。我们没有将任何东西设置为模块。我们设置Exports = function().....在new greet.js中。因此,模块。出口是空的。

技术上导出和模块。出口应该指向相同的参考(这是正确的!!)但是我们在赋值function()....时使用“=”到导出,这将在内存中创建另一个对象。因此,模块。输出和输出产生不同的结果。当涉及到输出时,我们无法覆盖它。

现在,想象你重写(这叫做突变) greet.js(指Renee answer)为

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

console.log(exports);
console.log(module.exports);

输出将是

{ a: [Function] }
{ a: [Function] }

正如你所看到的模块。Exports和Exports指向同一个引用,这是一个函数。如果你在导出上设置了一个属性,那么它将在模块上设置。因为在JS中,对象是通过引用传递的。

结论是始终使用模块。导出以避免混淆。 希望这能有所帮助。快乐编码:)

还有一件事可能有助于理解:

math.js

this.add = function (a, b) {
    return a + b;
};

client.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。

但是,如果您将实现更改为:

math.js

var add = function (a, b) {
    return a + b;
};

module.exports = {
    add: add
};

在这种情况下,它可以正常工作,但是,“this”不等于module。不再导出,因为创建了一个新对象。

console.log(this === module.exports); // false
console.log(this === exports); // true
console.log(module.exports === exports); // false

现在,require返回的是模块中定义的东西。出口,不再是这个或出口。

另一种方法是:

math.js

module.exports.add = function (a, b) {
    return a + b;
};

Or:

math.js

exports.add = function (a, b) {
    return a + b;
};

Rene回答了导出和模块之间的关系。Exports非常清楚,它都是关于javascript引用的。我只想补充一点:

我们可以在许多节点模块中看到这一点:

Var app = exports = module。Exports = {};

这将确保即使我们改变了模块。导出,我们仍然可以通过使这两个变量指向同一个对象来使用导出。

module是一个带有exports属性的纯JavaScript对象。exports是一个简单的JavaScript变量,它被设置为module.exports。 在文件的末尾,node.js基本上会'return'模块。导出到require函数。在Node中查看JS文件的简化方法如下:

var module = { exports: {} };
var exports = module.exports;

// your code

return module.exports;

如果你在导出上设置一个属性,比如export。a = 9;,这也会设置module.exports.a,因为在JavaScript中对象是作为引用传递的,这意味着如果你将多个变量设置为同一个对象,它们都是同一个对象;然后是exports和module。导出也是相同的对象。 但是如果你将exports设置为新的内容,它将不再被设置为module。导出,导出和模块。出口不再是同一个对象。