標籤:
前言:
Node.js的模組系統類別似於C/C++的檔案引用,可以聲明對象,也可以定義類 建立對象。
大家這麼理解,就簡單了。
定義:
為了讓Node.js的檔案可以相互調用,Node.js提供了一個簡單的模組系統。
模組是Node.js應用程式的基本組成部分,檔案和模組是一一對應的。
換言之,一個Node.js檔案就是一個模組,這個檔案可能是Javascript代碼、JSON或者編譯過的C/C++擴充。
執行個體一:
這個執行個體示範的是,在hello.js中建立一個方法,然後在主程式main.js中調用這個方法。
在Node.js中,建立一個模組非常簡單,大家跟著做一下就OK了。步驟如下:
步驟1:在E:\NodejsDemo檔案夾中,建立一個“hello.js”檔案,代碼如下:
1 exports.welcome = function(){2 console.log("Welcome to My Blog!");3 }
上述代碼中,我們使用exports對象,把welcome作為當前hello.js模組的提供者。
這樣,在其他的模組(js檔案)中,使用require命令,引入當前js檔案,即可直接存取welcome了。
步驟2:同目錄下,我們建立一個“main.js”檔案,作為要執行的主程式,引入hello.js檔案,執行welcome方法,代碼如下:
1 var Hello = require(‘./hello‘); // 引入hello.js模組(檔案)2 Hello.welcome(); // 訪問hello.js檔案中的welcome函數
上述代碼中,我們使用require函數,引入hello.js檔案。
然後,我們把引入的hello.js模組,存入了一個本地變數“Hello”中。
最後,我們使用本地變數“Hello”調用welcome函數,也就是訪問了hello.js模組中的welcome對外介面函數。
注意:這裡引入hello.js模組的時候,我們並沒有加尾碼,“./”表示目前的目錄,Node.js預設尾碼為“.js”。
步驟3:啟動DOS,進入目錄,執行“node main.js”運行主程式:
OK,大家發現,我們調用welcome方法之後,執行的是hello.js檔案中建立的welcome函數。
這個例子,大家想我開頭所說的理解,其實非常簡單。重點是exports和require。
- hello.js中的聲明 - exports.welcome = function(){...}
- main.js中的第一句話 - 引入hello.js:var Hello = require(‘./hello‘);
require命令我們在之前“Node.js 教程 02 - 經典的Hello World”已經接觸過了。
Node.js 提供了exports 和 require 兩個對象,其中 exports 是模組公開的介面,require 用於從外部擷取一個模組的介面,即所擷取模組的 exports 對象。
有沒有感覺,這個例子很像Java/.NET中的定義類、聲明對象、調用方法?
執行個體二:
Js大牛們知道,在Javascript中,我們可以“定義類、執行個體化對象”。
那我們如果想把一個對象封裝到模組中,應該怎麼辦呢?
按照上面的執行個體一,我們照葫蘆畫瓢:定義一個person類,引入執行個體化,並賦值,最後調用函數。
步驟1:建立一個“person.js”檔案,作為要引入的模組檔案,代碼如下:
1 function Person(){ 2 var name; 3 this.setName = function(_name){ 4 name = _name; 5 } 6 7 var url; 8 this.setUrl = function(_url){ 9 url = _url;10 }11 12 this.sayHello = function(){13 console.log("Welcome to my blog!\n" + url);14 console.log("My name is " + name +". Nice to meet you!");15 }16 }17 18 module.exports = Person;
上述代碼中,我們建立了一個Person對象,包含兩個需賦值參數及一個輸出函數。
重點是最後一句: module.exports = Person;
模組介面的唯一變化是使用 module.exports = Person 代替了 exports.world = function(){} 。
在外部參考該模組時,其介面對象就是要輸出的 Person 對象本身,而不是原先的 exports。
步驟2:建立主程式“main.js”,引入person.js模組,執行個體初始化並調用,代碼如下:
1 var Person = require(‘./person‘); 2 3 var person = new Person();4 person.setName("GuYing");5 person.setUrl("http://www.cnblogs.com/LonelyShadow");6 person.sayHello();
上述代碼中,我們第1行先引入“person.js”模組檔案,並存入本地的Person對象中。
第3行,執行個體化這個Person對象,將執行個體存入本地的person對象中。
第4-5行,為這個person對象賦值name和url參數。
第6行,訪問person對象的sayHello()函數,輸出結果。
Ps:到此為止,是不是覺得這個東西跟類和對象太相似了?O(∩_∩)O哈哈~
伺服器的模組放在那裡?
也許你已經注意到,我們之前在“Node.js 教程 03 - 建立HTTP伺服器”中已經在代碼中使用了模組了。像這樣:
1 var http = require("http");2 ...3 http.createServer(function(){});
Node.js中內建了一個叫做"http"的模組,我們在我們的代碼中請求它並把傳回值賦給一個本地變數。
這把我們的本地變數變成了一個擁有所有 http 模組所提供的公用方法的對象。
Node.js 的 require方法中的檔案尋找策略如下:
由於Node.js中存在4類別模組(原生模組和3種檔案模組),儘管require方法極其簡單,但是內部的載入卻是十分複雜的,其載入優先順序也各自不同。如所示:
從檔案模組緩衝中載入
儘管原生模組與檔案模組的優先順序不同,但是都不會優先於從檔案模組的緩衝中載入已經存在的模組。
從原生模組載入
原生模組的優先順序僅次於檔案模組緩衝的優先順序。
require方法在解析檔案名稱之後,優先檢查模組是否在原生模組列表中。
以http模組為例,儘管在目錄 下存在一個http/http.js/http.node/http.json檔案,require("http")都不會從這些檔案中載入,而是從原生 模組中載入。
原生模組也有一個緩衝區,同樣也是優先從緩衝區載入。如果緩衝區沒有被載入過,則調用原生模組的載入方式進行載入和執行。
從檔案載入
當檔案模組緩衝中不存在,而且不是原生模組的時候,Node.js會解析require方法傳入的參數,並從檔案系統中載入實際的檔案。
載入過程中的封裝和編譯細節在前一節中已經介紹過,這裡我們將詳細描述尋找檔案模組的過程,其中,也有一些細節值得知曉。
require方法接受以下幾種參數的傳遞:
- http、fs、path等,原生模組。
- ./mod或../mod,相對路徑的檔案模組。
- /pathtomodule/mod,絕對路徑的檔案模組。
- mod,非原生模組的檔案模組。
Node.js 教程 04 - 模組系統