模塊是構建應用程序的基礎,也使得函數和變量私有化,不直接對外暴露出來,接下來我們就要介紹Node的模塊化系統和它最常用的模式
為了讓Node.js的文件可以相互調用,Node.js提供了一個簡單的模塊系統。
模塊是Node.js 應用程序的基本組成部分,文件和模塊是一一對應的。換言之,一個 Node.js 文件就是一個模塊,這個文件可能是JavaScript 代碼、JSON 或者編譯過的C/C++ 擴展。
module的本質
我們都知道,JavaScript有一個很大的缺陷就是缺少namespacing的概念,程序運行在全局作用域下,很容易被內部應用程序的代碼或者是第三方依賴程序的數據所污染,一個很典型的解決方案就使通過IIFE來解決,本質上是利用閉包來解決
const module = (() => { const privateOne = () => { // ... } const privateTwo = () => { // ... } const exported = { publicOne: () => { // ... }, publicTwo: [] } return exported;})()console.log(module);通過上面的代碼,我們可以看出,module變量包含的只有對外暴露的API,然而剩下的module內容是對外不可見的,而這個也是Node module system最核心的思想。
Node modules 說明
CommonJS是一個致力于將JavaScript生態系統標準化的一個組織,它最出名的一個提議就是我們眾所周知的CommonJS modules,Node在本規范的基礎上構建了他自己的模塊系統,并且添加了一些自定義擴展,為了描述它是怎么工作的,我們可以使用上面所提到的module的本質的思想,自己做一個類似的實現。
自制一個module loader
下面的代碼主要是模仿Node原始的require()函數的功能
首先,我們創建一個函數用來加載一個module的內容,將它包裹在一個私有的作用域中
function loadModule(filename, module, require) { const warppedSrc = `(function(module, mexports, require) { ${fs.readFileSync(filename, 'utf-8')} })(module, module.exports, require)` eval(warppedSrc);}module的源代碼被包裝到一個函數中,如同IIFE那樣,這里的區別在于我們傳遞了一些變量給module,特指module、module.exports和require,注意的是我們的exports變量實質上是又module.exports初始化的,我們接下來會繼續討論這個
*在這個例子中,需要注意的是,我們使用了類似eval()或者是node的vm模塊,它們可能會導致一些代碼注入攻擊的安全性問題,所以我們需要特別注意和避免
接下來,讓我們通過實現我們的require()函數,來看看這些變量怎么被引入的
const require = (moduleName) => { console.log(`Required invoked for module: ${moduleName}`); const id = require.resolve(moduleName); if(require.cache[id]) { return require.cache[id].exports; } // module structure data const module = { exports: {}, id: id } // uodate cache require.cache[id] = module; // load the module loadModule(id, module, require); // return exported variables return module.exports;}require.cache = {};require.resolve = (moduleName) => { // resolve a full module id from the moduleName}
新聞熱點
疑難解答
圖片精選