一、模組

1.一個Node.js檔案就是一個模組,這個檔案可能 是JavaScript程式碼、JSON或者編譯過的C/C++擴充套件。

2.Node.js提供了exports和require兩個物件,其中exports是模組公開的介面,require用於從外部獲取一個模組的介面,即所獲取模組的exports物件。

3.一個檔案就是一個模組。

第一個例子,如何建立一個模組,先建立一個module.js檔案:

var name;
exports.setName = function(thyName){
	name = thyName;
};
exports.sayHello = function(){
	console.log('Hello' + name);
};
再在同一個目錄建立getmodule.js

var myModule = require('./module');
myModule.setName('BYVoid');
myModule.sayHello();
最後cmd進入該目錄執行node getmodule.js即可


原理:module.js通過exports物件把setName和sayHello作為模組的訪問介面,在getmodule.js中通過require('./module')載入這個模組,然後就直接訪問module.js中的exports物件的成員函數了。

延伸:因為require不會重複載入模組,也就是所無論呼叫多少次require獲得的模組都是同一個。例如修改getmodule.js看效果:

var myModule1 = require('./module');
myModule1.setName('BYVoid');
var myModule2 = require('./module');
myModule2.setName('BYVoid2');
myModule1.sayHello();
執行結果為:


原理:因為變數myModule1和myModule2都是指向同一個例項,因此myModule1.setName的結果被myModule2.setName覆蓋了。

第二個例子,覆蓋exports,把一個物件封裝到模組中:

新建一個singleobject.js

function Hello(){
	var name;
	this.setName = function(thyName){
		name = thyName;
	};
	this.sayHello = function(){
		console.log('HelloSingle' + name);	
	};
};
exports.Hello = Hello;

新建一個hello.js

function Hello(){
	var name;
	this.setName = function(thyName){
		name = thyName;	
	};
	this.sayHello = function(){
		console.log('HelloHello' + name);
	};
};
module.exports = Hello;
再新建一個gethello.js

var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
執行結果是:


模組介面唯一變化是使用module.exports=Hello代替了exports.Hello=Hello。

exports本身僅僅是一個普通的空物件,即{},它專門用來宣告介面,本質上是通過它為模組閉包的內部建立了一個有限的訪問介面。因為它沒有任何特殊的地方,所以可以用其他東西來替代,譬如上面例子中的Hello物件。

二、包

包:將某個獨立的功能封裝起來,用於釋出、更新、依賴管理和版本控制。

Node.js對包只要頂層目錄下有package.json,並符合一些規範即可。

模組與檔案是一一對應的,最簡單的包就是一個作為資料夾的模組。

建立一個例子說明作為資料夾的模組:
新建一個資料夾somepackage在其中建立index.js

exports.hello = function(){
	console.log('Hello.');
};
然後在somepackage資料夾之外建立getpackage.js

var somePackage = require('./somepackage');
somePackage.hello();
cmd進入存放getpackage.js地址,node getpackage.js


原理:這種方法可以把資料夾封裝為一個模組,即所謂的包。包通常是一些模組的集合,在模組的基礎上提供了更高層的抽象,相當於提供一些固定介面的函式庫。

通過定製package.json,可以建立更復雜、更完善、更符合規範的包用於釋出,建立一個例子說明如下:
在somepackage資料夾下面,新建立一個叫做package.json的檔案

{
	"main" : "./lib/interface.js"
}

再在這個資料夾目錄下面新建一個lib資料夾和在下面新建一個interface.js

exports.hello = function(){
	console.log('HelloLib');
};
cmd進入存放getpackage.js地址,node getpackage.js

Node.js在呼叫某個包時,會首先檢查包中package.json檔案的main欄位,將其作為包的介面模組,如果package.json或main欄位不存在,會嘗試尋找index.js或index.node作為包的介面。【如果既沒有在package.json裡面說明又沒有在index.js或index.node中,就會報找不到此檔案的錯誤哦】

三、包管理器npm

1.獲取一個包:npm install/i package_name比如:npm install express或 npm i express。npm預設情況會從http://npmjs.org搜尋下載包,將包安裝到當前目錄的node_modules子目錄下面

2.本地模式和全域性模式

(1)如果把包安裝到全域性,可以提高程式的重複利用程度,避免同樣的內容多份副本,但壞處是難以處理不同版本依賴

  如果把包安裝到當前目錄,或者說本地,則不會有不同程式依賴不同版本的包的衝突問題,同時減輕了包作者API相容性壓力,但缺陷是同一個包可能會被安裝很多次。

(2)全域性模式獲取一個包:npm install/i -g package_name

多數情況下並不是因為許多程式都可能用到它,為了減少多重副本而使用全域性模式,而是因為本地模式不會註冊PATH環境變數。npm本地模式僅僅是把包安裝到node_modules子目錄下,其中的bin目錄沒有包含到PATH環境變數中,不能直接在命令列中呼叫。而全域性模式下的supervisor.js就可以直接在命令列中執行supervisor XXX.js即可監控程式碼改動了。