任何一門編程語言,當代碼越寫越多時,人們就會考慮如何將代碼進行分類組織。通常情況下,都會講代碼按照功能進行拆分並保存在不同目錄及文件中,通過相互引用來達到代碼復用。那么這個時候不可避免的就會遇到全局變量可能會被污染的問題。通常情況下,很多語言都會提供一個叫做命名空間的概念,從而形成了模塊這個概念。然而JS天生並沒有提供命名空間這樣一個機制。於是有熱心的開發者提供了CommonJS和AMD,CMD等多種規范。其中NodeJS就是遵循CommonJS規范的。而現在ES6也已經推出,它提供的模塊機制是綜合了各家的優勢后設立的另一套規范。
現在我們來細細聊NodeJS中的模塊機制。在NodeJS中,Node模塊允許開發者從被引入的文件中選擇要暴露給外界的函數或變量。機制是通過exports對象的屬性或module.exports屬性進行模塊暴露。NodeJS模塊系統正是通過這樣一種機制來避免了全局作用域的污染,從而避免了命名沖突。接下來從幾個方面來講解模塊。
一、創建模塊
NodeJS中的模塊可以是一個文件,也可以是一個包含多文件的目錄。如果模塊是一個目錄,那么Node就會在該目錄下查找一個叫index.js的文件作為模塊的入口。當然這個文件名index.js也是可以通過package.json文件進行配置的。通過在exports對象上設置屬性的方式來創建模塊。
var canadianDollar = 0.91; function roundTwoDecimals(amount){ return Math.round(amount*100)/100; } exports.canadianToUS = function(canadian){ return roundTwoDecimals(canadian * canadianDollar); } exports.USToCanadian = function(us){ return roundTwoDecimals(us / canadianDollar); }
通過require(path)的方式來加載模塊。注意如果是自定義文件模塊並且處在同一目錄下,那么一定要記住請使用 " ./ " 這個相對路徑標識。
var currency = require('./currency'); console.log("50 Canadian dollars equals this amount of US dollars:"); console.log(currency.canadianToUS(50)); console.log("30 US dollar equals this amount of Canadian dollars:"); console.log(currency.USToCanadian(30));
也可以通過module.exports來創建模塊
function Currency(canadianDollar){ this.canadianDollar = canadianDollar; } Currency.prototype.roundTwoDecimals = function(amount){ return Math.round(amount*100)/100; }; Currency.prototype.canadianToUS = function(canadian){ return this.roundTwoDecimals(canadian * this.canadianDollar); }; Currency.prototype.USToCanadian = function(us){ return this.roundTwoDecimals(us / this.canadianDollar); }; module.exports = Currency;
這樣通過require方法引入的模塊就是一個構造函數
var Currency = require("./currency"); var canadianDollar = 0.91; var currency = new Currency(canadianDollar); console.log(currency.canadianToUS(50));
模塊最終導出的是module.exports對象,而模塊內部隱藏了一句代碼exports = module.exports 所以不要輕易給exports重新設置引用關系。
module對象在所有的Node程序中都存在,但是每個module對象都僅僅存在於它當前的模塊內。也就是說只存在於模塊作用域內。
二、安裝與加載模塊
從npm安裝第三方模塊使用 npm install [package] 命令
通過require() 來加載模塊
通過npm search [package] 命令來查找模塊
同理,require對象也不是全局變量,而是每個模塊內部的一個對象,作用於模塊內。
require對象的方法
1. require.cache
當模塊被引入時,會被緩存到這個對象中,通過 delete 可以從該對象中刪除鍵值,這樣下次調用 require()時就會重新加載模塊。不適用於核心模塊,常用於第三方模塊。
2. require.resolve()
使用內部的require()機制來查找模塊的位置,但是不會加載模塊,只是返回解析后的模塊文件絕對路徑( __filename )。這個絕對路徑也是module對象中的Id屬性。
模塊加載的內部原理
通常在package.json文件中會通過main屬性來指定模塊入口文件,這樣加載模塊時會考慮這個默認文件。