2017-08-01 19 views
5

我一直在浏览一些关于Node.js的在线教程。我的理解是,在使用功能require(./file-path),节点获取该文件的内容和包装了一个调用立即功能为什么我们需要传递module.exports作为参数,因为我们已经将模块作为参数传递了?

(function(exports, require, module, __filename, __dirname) { 
    // content 
}()) 

里面我明白exportsmodule.exports之间的差异。这就是我在互联网上看到的关于搜索上述问题的全部内容。但是我的问题是,为什么我们需要将module.exportsmodule传递给包装IIFE?我们可以单独通过模块,然后从中获取module.exports。这样做有什么优势吗?通常,当我们将一个对象传递给一个函数时,我们不需要另外通过object.property

回答

3

答案是:历史原因。

你说得对,我们可能只有moduleexports不会被需要,但它仍然是为了向后兼容。

它曾经是模块包装器在几乎每个补丁版本中都发生变化的时候。

在节点0.1.11模块封装为:

var wrapper = "function (__filename) { "+ 
       " var onLoad; "+ 
       " var onExit; "+ 
       " var exports = this; "+ 
       content+ 
       "\n"+ 
       " this.__onLoad = onLoad;\n"+ 
       " this.__onExit = onExit;\n"+ 
       "};\n"; 

参见:https://github.com/nodejs/node/blob/v0.1.11/src/node.js#L167#L177

正如你可以看到exports是一样的this的包装函数被调用。您无法将其与新对象交换,甚至无法为其添加一些保留键 - 例如,您无法安全地导出名为__onExit的属性。

然后在0.1.12是:

var wrapper = "function (__filename, exports) { " + content + "\n};"; 

参见:https://github.com/nodejs/node/blob/v0.1.12/src/node.js#L243-L245

这里exports是作为一个参数提供的对象,但你不能用一个新的对象换了,你只能添加或删除你得到的对象的属性。

然后0.1.13是第一个具有此,即requireinclude

var wrapper = "function (__filename, exports, require, include) { " + content + "\n};"; 

参见:https://github.com/nodejs/node/blob/v0.1.13/src/node.js#L225-L227

然后0.1.14是第一个具有__module(用下划线)在包装(和下降include):

var wrapper = "var __wrap__ = function (__module, __filename, exports, require) { " 
      + content 
      + "\n}; __wrap__;"; 

见:https://github.com/nodejs/node/blob/v0.1.14/src/node.js#L280-L284

而0.1。16是第一个在纸上出现module参数(不带下划线):

var wrapper = "var __wrap__ = function (exports, require, module, __filename) { " 
      + content 
      + "\n}; __wrap__;"; 

参见:https://github.com/nodejs/node/blob/v0.1.16/src/node.js#L444-L448

它之后已经改变了很多次,但这个就是module得到了介绍制作时间该exports不再需要更多的,但仍然有用的快捷方式,让您的使用:的

exports.a = 1; 
exports.b = 2; 
exports.c = 3; 

代替:

module.exports.a = 1; 
module.exports.b = 2; 
module.exports.c = 3; 

但实际上如果没有exports然后一个通常会写:

const exports = module.exports; 
exports.a = 1; 
exports.b = 2; 
exports.c = 3; 

或更可能:

module.exports = { 
    a: 1, 
    b: 2, 
    c: 3, 
}; 

,或者有在静态分析工具进行一些检查:

const a = 1; 
const b = 2; 
const c = 3; 
module.exports = { a, b, c }; 

有很多方法可以做到这一点,它很漂亮灵活的机制。

+0

打败我吧。比我想起的还早。 – OrangeDog

2

最初它只是exportsrequire。 稍后,module以向后兼容的方式添加,以允许(除其他外)完全覆盖导出对象。

+0

让我看看我能否找到改变。我认为它在v0.6左右。 – OrangeDog

+0

后来当他们添加模块时,为什么他们没有删除module.exports呢?他们可以从模块对象中获取它。 –

+0

@MINWINVINCENT因为这会破坏使用新平台的旧模块和使用旧平台的新模块。 – OrangeDog