Javascript “你做什么?”;“出口”模块;及;出口.方法“;在NodeJS/Express中是什么意思?

Javascript “你做什么?”;“出口”模块;及;出口.方法“;在NodeJS/Express中是什么意思?,javascript,node.js,express,module,export,Javascript,Node.js,Express,Module,Export,查看express框架中的NodeJS,有两行代码我不理解(这些代码行几乎是所有NodeJS文件的典型代码) 及 我知道第一段代码允许文件中的其余函数向NodeJS应用程序公开,但我不清楚它是如何工作的,或者这行代码的意思 exports和module.exports实际上是什么意思 我相信第二段代码允许文件中的函数访问方法,但它究竟是如何做到这一点的 基本上,这些神奇的词语是什么:模块和导出?更具体地说: 模块是文件中的全局范围变量 因此,如果您调用require(“foo”),那么: //

查看
express
框架中的
NodeJS
,有两行代码我不理解(这些代码行几乎是所有NodeJS文件的典型代码)

我知道第一段代码允许文件中的其余函数向NodeJS应用程序公开,但我不清楚它是如何工作的,或者这行代码的意思

exports
module.exports
实际上是什么意思

我相信第二段代码允许文件中的函数访问
方法
,但它究竟是如何做到这一点的

基本上,这些神奇的词语是什么:
模块
导出

更具体地说:

模块
是文件中的全局范围变量

因此,如果您调用
require(“foo”)
,那么:

// foo.js
console.log(this === module); // true
它的作用方式与
窗口
在浏览器中的作用方式相同

还有另一个名为
global
的全局对象,您可以在任何需要的文件中写入和读取该对象,但这涉及到全局范围的变化,这就是EVIL

exports
是存在于
模块上的变量。exports
。它基本上就是在需要文件时导出的内容

// foo.js
module.exports = 42;

// main.js
console.log(require("foo") === 42); // true
导出本身存在一个小问题。_global scope context+和
模块
不相同。(在浏览器中,全局范围上下文和
窗口
是相同的)


模块是一个对象,表示特定源文件想要公开的内容。在c/c++世界中没有类似于头文件的东西,而是通过定义此对象来描述模块导出的内容。然后,节点运行时使用此对象确定模块的哪些内容是“公共的”


这与在编译世界中从dll导出函数的概念类似。您必须明确定义外部世界可以访问哪些函数。这有助于封装,并让您以一种干净的方式组织库。

要扩展Raynos的答案

exports
基本上是
模块的别名。exports
-我建议不要使用它。通过在模块上设置方法和属性,您可以公开模块中的方法和属性。导出如下所示:

//file 'module1.js'
module.exports.foo = function () { return 'bar' }
module.exports.baz = 5
//module.js
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);
然后您可以在代码中访问它:

var module1 = require('module1')
console.log(module1.foo())
console.log(module1.baz)
您还可以覆盖
模块。完全导出
以根据需要提供单个对象:

//glorp.js
module.exports = function () {
  this.foo = function () { return 'bar' }
  this.baz = 5
  return this // need to return `this` object here
}
现在您有了一个很好的原型:

var g1 = new require('glorp')()
console.log(g1.foo())
console.log(g1.baz)
使用
模块还有很多其他方法。导出
需要
。请记住,
require('foo')
始终返回相同的实例,即使您多次调用它

注 为了让以下各项发挥作用

var g1 = new require('glorp')()
console.log(g1.foo())
console.log(g1.baz) 
必须在分配给
模块的函数中返回。导出
。否则,您将得到一个
TypeError

console.log(g1.foo())
          ^
TypeError: Cannot read property 'foo' of undefined

您可以在node.js源代码中找到最佳答案。 如果有人需要你的js模块, 您的脚本按节点转换为函数,如下所示(请参见src/node.js)

节点将包装您的脚本。然后将按如下方式执行上述脚本:

//file 'module1.js'
module.exports.foo = function () { return 'bar' }
module.exports.baz = 5
//module.js
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);
所以在你的剧本里

exports is just module.exports.
在脚本中,您可以向该导出对象添加一些内容(函数..)。 require函数将返回此对象。这是node.js的模块系统(commonJS规范)


但请注意不要修改module.exports。否则,您当前的导出将毫无意义。

模块的代码包装在模块中。导出(该模块可能由其他模块组成)。 构建模块的方法有很多,但这是一种非常常见的方法(也是我个人的最爱)


您可以解释为什么导出=模块。导出=路由器;是否使用了构造?这很不幸,因为到目前为止我看到的大多数源代码(我承认这是非常有限的)使用它,包括连接。js@ShaneCourtrille他似乎想设置
模块。将
导出到
路由器
,然后想将属性添加到
导出
,而不是
路由器
,这就是他为什么要执行这三项操作的原因。我认为这是一种愚蠢的编码方式,因为他可以直接将属性添加到
Router
。我不敢相信我已经使用Node.JS这么长时间了,并且一直认为全局对象是
process
而不是
module
+1@ShaneCourtrille这个答案更详细地解释了原因:
//module.js
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);
exports is just module.exports.
// Dependencies
// const module = require('module');

// Module object
var foo = {}

// Internal property
foo._a = 'a';

// "Public" property
foo.b = 'b';

// Method
foo.fu = function() { return 'fu' };

// Export
module.exports = foo;