node.js module初步理解


 在開發一個復雜的應用程序的時候,我們需要把各個功能拆分、封裝到不同的文件,在需要的時候引用該文件。沒人會寫一個幾萬行代碼的文件,這樣在可讀性、復用性和維護性上都很差,幾乎所有的編程語言都有自己的模塊組織方式,比如Java中的包、C#中的程序集等,node.js使用模塊和包來組織,其機制實現參照了CommonJS標准,雖未完全遵守,但差距不大,使用起來非常簡單。

什么是模塊

在node.js中模塊與文件是一一對應的,也就是說一個node.js文件就是一個模塊,文件內容可能是我們封裝好的一些JavaScript方法、JSON數據、編譯過的C/C++拓展等,在關於node.js的誤會提到過node.js的架構

其中http、fs、net等都是node.js提供的核心模塊,使用C/C++實現,外部用JavaScript封裝。

創建、加載模塊

模塊在node.js中的概念很簡單,看看如何創建一個我們自己的模塊供開發復用。

在node.js中創建模塊非常簡單,一個文件就是一個模塊,所以我們創建一個test.js文件就創建了一個模塊

test.js

var name='';

function setName(n){
    name=n;
} 

function printName(){
    console.log(name);
}

 問題是怎么使外部訪問這個module,我們知道客戶端的JavaScript使用script標簽引入JavaScript文件就可以訪問其內容了,但這樣帶了的弊端很多,最大的就是作用域相同,產生沖突問題,以至於前端大師們想出了立即執行函數等方式,利用閉包解決。node.js使用exports和require對象來解決對外提供接口和引用模塊的問題。

我們可以把模塊中希望被外界訪問的內容定義到exports對象中,對test.js稍作修改就可以了

test.js

var name='';

function setName(n){
    name=n;
} 

function printName(){
    console.log(name);
}

exports.setName=setName;
exports.printName=printName;

這樣我們在相同路徑下創建index.js,使用require引用一下test.js module

index.js

var test=require('./test');

test.setName('Byron');
test.printName();

exports一個對象

有時候我們希望模塊對外提供的使一個對象,修改一下test.js

test.js

var Student=function(){
    var name='';

     this.setName=function(n){
        name=n;
    }; 

    this.printName=function(){
        console.log(name)    ;
    };
};

exports.Student=Student;

 這樣我們對外提供了一個Student類,在使用的時候需要這樣

var Student=require('./test').Student;
var student=new Student();
student.setName('Byron');
student.printName();

 require('./test').Student 很丑陋的樣子,我們可以簡單修改一下exports方式,使require優雅一些

test.js

var Student=function(){
    var name='';

     this.setName=function(n){
        name=n;
    }; 

    this.printName=function(){
        console.log(name)    ;
    };
};

module.exports=Student;

 這樣我們的require語句就可以優雅一些了

var Student=require('./test');

 

很神奇的樣子,不是說好的exports是模塊公開的接口嘛,那么module.exports是什么東西?

module.exports與exports

事實的情況是醬紫的,其實module.exports才是模塊公開的接口,每個模塊都會自動創建一個module對象,對象有一個modules的屬性,初始值是個空對象{},module的公開接口就是這個屬性——module.exports。既然如此那和exports對象有毛線關系啊!為什么我們也可以通過exports對象來公開接口呢?

為了方便,模塊中會有一個exports對象,和module.exports指向同一個變量,所以我們修改exports對象的時候也會修改module.exports對象,這樣我們就明白網上盛傳的module.exports對象不為空的時候exports對象就自動忽略是怎么回事兒了,因為module.exports通過賦值方式已經和exports對象指向的變量不同了,exports對象怎么改和module.exports對象沒關系了。

大概就是這么過程

module.exports=exports={};
......

module.exports=new Object();

exports=xxx;//和new Object沒有關系了,最后返回module.exports,所以改動都無效了

一次加載

無論調用多少次require,對於同一模塊node.js只會加載一次,引用多次獲取的仍是相同的實例,看個例子

test.js

var name='';

function setName(n){
    name=n;
} 

function printName(){
    console.log(name);
}

exports.setName=setName;
exports.printName=printName;

 

index.js

var test1=require('./test'),
    test2=require('./test');

test1.setName('Byron');
test2.printName();

 

 

執行結果並不是'',而是輸出了test1設置的名字,雖然引用兩次,但是獲取的是一個實例

require搜索module方式

node.js中模塊有兩種類型:核心模塊和文件模塊,核心模塊直接使用名稱獲取,比如最長用的http模塊

var http=require('http');

 

在上面例子中我們使用了相對路徑 './test'來獲取自定義文件模塊,那么node.js有幾種搜索加載模塊方式呢?

  1. 核心模塊優先級最高,直接使用名字加載,在有命名沖突的時候首先加載核心模塊
  2. 文件模塊只能按照路徑加載(可以省略默認的.js拓展名,不是的話需要顯示聲明書寫)
    1. 絕對路徑
    2. 相對路徑
  3. 查找node_modules目錄,我們知道在調用 npm install <name> 命令的時候會在當前目錄下創建node_module目錄(如果不存在) 安裝模塊,當 require 遇到一個既不是核心模塊,又不是以路徑形式表示的模塊名稱時,會試圖 在當前目錄下的 node_modules 目錄中來查找是不是有這樣一個模塊。如果沒有找到,則會 在當前目錄的上一層中的 node_modules 目錄中繼續查找,反復執行這一過程,直到遇到根 目錄為止。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM