Node應用是由模塊組成的,Node遵循了CommonJS的模塊規范,來隔離每個模塊的作用域,使每個模塊在它自身的命名空間中執行。
CommonJS規范的主要內容:
模塊必須通過 module.exports 導出對外的變量或接口,通過 require() 來導入其他模塊的輸出到當前模塊作用域中。
CommonJS模塊的特點:
(1)所有代碼運行在當前模塊作用域中,不會污染全局作用域 (2)模塊同步加載,根據代碼中出現的順序依次加載 (3)模塊可以多次加載,但是只會在第一次加載時運行一次,然后運行結果就被緩存了,以后再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。
一個簡單的例子:
//demo.jsmodule.exports.name = 'Aphasia';module.exports.getAge = function(age){ console.log(age)};//需要引入demo.js的其他文件var person = require('./demo.js')根據CommonJS規范,每一個文件就是一個模塊,在每個模塊中,都會有一個module對象,這個對象就指向當前的模塊。module對象具有以下屬性:
(1)id:當前模塊的bi (2)exports:表示當前模塊暴露給外部的值 (3)parent: 是一個對象,表示調用當前模塊的模塊 (4)children:是一個對象,表示當前模塊調用的模塊 (5)filename:模塊的絕對路徑 (6)paths:從當前文件目錄開始查找node_modules目錄;然后依次進入父目錄,查找父目錄下的node_modules目錄;依次迭代,直到根目錄下的node_modules目錄 (7)loaded:一個布爾值,表示當前模塊是否已經被完全加載
示例:
module.js文件
執行node module.js文件
從上面的例子我們也能看到,module對象具有一個exports屬性,該屬性就是用來對外暴露變量、方法或整個模塊的。當其他的文件require進來該模塊的時候,實際上就是讀取了該模塊module對象的exports屬性。
簡單的使用示例
module.exports = 'Aphasia';module.exports.name = 'Aphasia';module.exports = function(){ //dosomething}module.exports = { name: 'Aphasia', getAge: function(){ //dosomething }}為什么還有個exports變量呢?一開始我也很郁悶,既然module.exports就能滿足所有的需求,干嘛還要個exports呢。其實,原因很簡單–就是為了簡單。當然,二者之間還存在一些差異,聽我慢慢道來。
(1)exports其實是指向module.exports,也就是相當于
exports = module.exports;(2)我們可以將二者的關系可以理解成這是一種引用關系。由于這樣的引用關系可知,既然exports始終指向的是module.exports,那我們就不能給exports直接進行賦值操作(不能亂指),因為這樣的操作會導致exports不再指向module.exports。
//以下操作都是不允許的exports = 'Aphasia';exports = function(){ console.log('Aphasia')}//這些操作都是合法的exports.name = 'Aphasia';exports.getName = function(){ console.log('Aphasia')}(1)exports用來拋出一個接口,require就是用來引入這個模塊拋出的接口,返回引入模塊的exports對象,如果沒有找到該模塊,就會報錯。 (2)使用require引入的文件,文件名后綴默認為.js
既然是用來引入一個模塊,就需要有一定的查找規則以確定需要引入的模塊究竟存在哪里。
根據上面的流程圖,其實可以看出以下幾點: (1)被引入的模塊優先從緩存中加載,命中緩存直接加載;未命中,之后會被加入緩存。 (2)如果不是node的原生模塊,則根據傳入到require中的參數引入模塊。這一過程的查找規則如下:
如果路徑是以/
開始的絕對路徑,就從該項目的絕對路徑中去加載該模塊。比如:require(“/demo/lib/api.js”),就會從/demo/lib/api.js
中去加載該模塊 如果路徑是以./
開始的相對路徑,則表示加載的是一個位于相對路徑(跟當前執行腳本的位置相比)的模塊文件。比如,require(‘./circle’)將加載當前腳本同一目錄的circle.js 新聞熱點
疑難解答