為了讓Node.js的文件可以相互調(diào)用蛛株,Node.js提供了一個簡單的模塊系統(tǒng)。模塊是Node.js應(yīng)用程序的基本組成部分翰苫,文件和模塊是一一對應(yīng)的止邮。換言之,一個Node.js文件就是一個模塊奏窑,這個文件可能是JavaScript 代碼导披、JSON 或者編譯過的C/C++ 擴展。
創(chuàng)建模塊
在 Node.js 中埃唯,創(chuàng)建一個模塊非常簡單撩匕,如下我們創(chuàng)建一個 main.js
文件,代碼如下:
var hello = require('./hello');
hello.world();
以上實例中墨叛,代碼require('./hello')引入了當(dāng)前目錄下的hello.js
文件(./為當(dāng)前目錄止毕,node.js默認后綴為js)。Node.js 提供了exports和require兩個對象漠趁,其中exports是模塊公開的接口扁凛,require用于從外部獲取一個模塊的接口,即所獲取模塊的 exports 對象闯传。接下來我們就來創(chuàng)建hello.js
文件谨朝,代碼如下:
exports.world = function() {
console.log('Hello World');
}
在以上示例中,hello.js 通過 exports 對象把 world 作為模塊的訪問接口甥绿,在 main.js 中通過 require('./hello') 加載這個模塊字币,然后就可以直接訪 問 hello.js 中 exports 對象的成員函數(shù)了。有時候我們只是想把一個對象封裝到模塊中共缕,格式如下:
module.exports = function() {
// ...
}
例如:
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
這樣就可以直接獲得這個對象了:
//main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
模塊接口的唯一變化是使用 module.exports = Hello 代替了exports.world = function(){}洗出。 在外部引用該模塊時,其接口對象就是要輸出的 Hello 對象本身,而不是原先的 exports。
服務(wù)端的模塊放在哪里
也許你已經(jīng)注意到,我們已經(jīng)在代碼中使用了模塊了。像這樣:
var http = require("http");
...
http.createServer(...);
Node.js中自帶了一個叫做"http"的模塊幻赚,我們在我們的代碼中請求它并把返回值賦給一個本地變量。
這把我們的本地變量變成了一個擁有所有 http 模塊所提供的公共方法的對象凯旋。
Node.js 的 require方法中的文件查找策略如下:
由于Node.js中存在4類模塊(原生模塊和3種文件模塊)择诈,盡管require方法極其簡單,但是內(nèi)部的加載卻是十分復(fù)雜的俏竞,其加載優(yōu)先級也各自不同绸硕。如下圖所示:
從文件模塊緩存中加載
盡管原生模塊與文件模塊的優(yōu)先級不同堂竟,但是都不會優(yōu)先于從文件模塊的緩存中加載已經(jīng)存在的模塊。
從原生模塊加載
原生模塊的優(yōu)先級僅次于文件模塊緩存的優(yōu)先級玻佩。require方法在解析文件名之后出嘹,優(yōu)先檢查模塊是否在原生模塊列表中。以http模塊為例咬崔,盡管在目錄下存在一個http/http.js/http.node/http.json文件税稼,require("http")都不會從這些文件中加載,而是從原生模塊中加載垮斯。
原生模塊也有一個緩存區(qū)郎仆,同樣也是優(yōu)先從緩存區(qū)加載。如果緩存區(qū)沒有被加載過兜蠕,則調(diào)用原生模塊的加載方式進行加載和執(zhí)行扰肌。
從文件加載
當(dāng)文件模塊緩存中不存在,而且不是原生模塊的時候熊杨,Node.js會解析require方法傳入的參數(shù)曙旭,并從文件系統(tǒng)中加載實際的文件,加載過程中的包裝和編譯細節(jié)在前一節(jié)中已經(jīng)介紹過晶府,這里我們將詳細描述查找文件模塊的過程桂躏,其中,也有一些細節(jié)值得知曉川陆。
require方法接受以下幾種參數(shù)的傳遞:
- http剂习、fs、path等原生模塊书劝。
- ./mod或../mod进倍,相對路徑的文件模塊。
- /pathtomodule/mod购对,絕對路徑的文件模塊猾昆。
- mod,非原生模塊的文件模塊骡苞。