2017-08-01 20 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