Node.js的模塊系統相似於C/C++的文件引用,能夠聲明對象,也能夠定義類 建立對象。html
你們這麼理解,就簡單了。node
爲了讓Node.js的文件能夠相互調用,Node.js提供了一個簡單的模塊系統。json
模塊是Node.js應用程序的基本組成部分,文件和模塊是一一對應的。緩存
換言之,一個Node.js文件就是一個模塊,這個文件多是Javascript代碼、JSON或者編譯過的C/C++擴展。服務器
這個實例演示的是,在hello.js中建立一個方法,而後在主程序main.js中調用這個方法。函數
在Node.js中,建立一個模塊很是簡單,你們跟着作一下就OK了。步驟以下:post
步驟1:在E:\NodejsDemo文件夾中,建立一個「hello.js」文件,代碼以下:ui
1 exports.welcome = function(){ 2 console.log("Welcome to My Blog!"); 3 }
上述代碼中,咱們使用exports對象,把welcome做爲當前hello.js模塊的訪問接口。this
這樣,在其餘的模塊(js文件)中,使用require命令,引入當前js文件,便可直接訪問welcome了。url
步驟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。
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方法接受如下幾種參數的傳遞: