2011-05-24 127 views
49

查看NodeJSexpress框架的随机source file,有两行代码我不明白(这些代码行几乎是所有NodeJS文件的典型代码)。NodeJS/Express中的“module.exports”和“exports.methods”是什么意思?

/** 
* Expose `Router` constructor. 
*/ 

exports = module.exports = Router; 

/** 
* Expose HTTP methods. 
*/ 

var methods = exports.methods = require('./methods'); 

我明白的代码第一块允许的功能,其余在文件中被暴露于应用程序的NodeJS,但我不明白确切地说它是如何工作的,或者行中的代码意味着什么。

exportsmodule.exports究竟是什么意思?

我相信第二张的代码允许文件中的函数访问methods,但同样,究竟它是如何做到这一点。

基本上,这些是什么神奇的话:moduleexports

回答

76

更具体:

module是一个文件中的全局范围变量。

所以,如果你require("foo")则:

// foo.js 
console.log(this === module); // true 

它的行为以同样的方式,在浏览器window行为。

还有一种叫global,你可以写和从任何你想要的文件的读取全局对象,但涉及突变全球范围内,这是EVIL

exports是住在module.exports的变量。这基本上是你出口当需要一个文件。

// foo.js 
module.exports = 42; 

// main.js 
console.log(require("foo") === 42); // true 

自己有一个小问题exports。 _global scope context +和module而不是相同。 (在浏览器中,全局范围上下文和window是相同的)。

// foo.js 
var exports = {}; // creates a new local variable called exports, and conflicts with 

// living on module.exports 
exports = {}; // does the same as above 
module.exports = {}; // just works because its the "correct" exports 

// bar.js 
exports.foo = 42; // this does not create a new exports variable so it just works 

Read more about exports

+0

你可以解释为什么exports = module.exports = Router;构造用于? – 2012-02-02 20:11:30

+1

@ShaneCourtrille如果它只是不好的代码。 – Raynos 2012-02-02 20:57:04

+0

这很不幸,因为目前为止我所见过的大部分源代码(我承认这是非常有限的)使用它,包括connect.js – 2012-02-02 21:38:29

1

模块是代表特定的源文件,要公开曝光什么的对象。通过定义此对象,您可以描述模块导出的方式,而不是类似于c/C++世界中的头文件。节点运行时然后使用这个对象来确定你的模块是“公共的”。'

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

33

要扩大Raynos的答案...

exports基本上是一个别名module.exports - 我建议只是不使用它。您可以将其设定在module.exports暴露从一个模块的方法和属性,如下所示:

//file 'module1.js' 
module.exports.foo = function() { return 'bar' } 
module.exports.baz = 5 

然后你访问它在你的代码:

var module1 = require('module1') 
console.log(module1.foo()) 
console.log(module1.baz) 

您还可以覆盖module.exports完全可以根据要求简单提供单个物体:

//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) 

还有无数其他的方式与module.exportsrequire玩。请记住,即使您多次调用它,require('foo')始终会返回相同的实例

对于下面的工作,

var g1 = new require('glorp')() 
console.log(g1.foo()) 
console.log(g1.baz) 

this在分配给module.exports的函数返回。否则,你会得到一个TypeError

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

您可以在node.js的源代码中的最佳答案。 如果有人需要您的js模块,您的脚本将按如下方式变为一个功能(请参阅src/node.js)。

// require function does this.. 
(function (exports, require, module, __filename, __dirname) { 
    ... your javascript contents... 
}); 

节点将包装您的脚本。然后,上面的脚本将如下执行:

//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。否则你目前的出口将毫无意义。