Nodejs學習筆記(三)--- 模塊


目錄

簡介及資料

通過Node.js的官方API可以看到Node.js本身提供了很多核心模塊 http://nodejs.org/api/ ,這些核心模塊被編譯成二進制文件,可以require('模塊名')去獲取;核心模塊具有最高的加載優先級(有模塊與核心模塊同名時會體現)

(本次主要說自定義模塊)

 

Node.js還有一類模塊為文件模塊,可以是JavaScript代碼文件(.js作為文件后綴)、也可以是JSON格式文本文件(.json作為文件后綴)、還可以是編輯過的C/C++文件(.node作為文件后綴);

 

文件模塊訪問方式通過require('/文件名.后綴')    require('./文件名.后綴')    requrie('../文件名.后綴') 去訪問,文件后綴可以省略;以"/"開頭是以絕對路徑去加載,以"./"開頭和以"../"開頭表示以相對路徑加載,而以"./"開頭表示同級目錄下文件,

前面提到文件后綴可以省略,Nodejs嘗試加載的優先級 js文件 > json文件 > node文件

創建一個自定義模塊

   以一個計數器為例

var outputVal  = 0;     //輸出值
var increment = 1;    //增量

/* 設置輸出值 */
function seOutputVal (val) {
    outputVal = val;
}

/* 設置增量 */
function setIncrement(incrementVal){
    increment = incrementVal;
}

/* 輸出 */
function printNextCount()
{    
    outputVal += increment;
    console.log(outputVal) ;
}

function printOutputVal() {
    console.log(outputVal);
}
exports.seOutputVal = seOutputVal;
exports.setIncrement = setIncrement;

module.exports.printNextCount = printNextCount;
自定義模塊 示例源碼

示例中重點在於exports和module.exports;提供了外部訪問的接口,下面調用一下看看效果吧

調用自定義模塊

 

/*
    一個Node.js文件就是一個模塊,這個文件可能是Javascript代碼、JSON或者編譯過的C/C++擴展。
    重要的兩個對象:
    require是從外部獲取模塊
    exports是把模塊接口公開    
*/
var counter = require('./1_modules_custom_counter');

console.log('第一次調用模塊[1_modules_custom_counter]');

counter.seOutputVal(10);               //設置從10開始計數
counter.setIncrement (10);             //設置增量為10

counter.printNextCount();
counter.printNextCount();
counter.printNextCount();
counter.printNextCount();

/*
    require多次調用同一模塊不會重復加載
*/
var counter = require('./1_modules_custom_counter');

console.log('第二次調用模塊[1_modules_custom_counter]');
counter.printNextCount();
自定義模式調用 源碼

運行可以發現通過exports和module.exports對外公開的方法都可以訪問!

示例中可以看到,我兩次通過require('./1_modules_custom_counter')獲取模塊,但是第二次引用后調用printNextCount()方法確從60開始~~~

原因是node.js通過requirerequire多次調用同一模塊不會重復加載,Node.js會根據文件名緩存所有加載過的文件模塊,所以不會重新加載了

注意:通過文件名緩存是指實際文件名,並不會因為傳入的路徑形式不一樣而認會是不同的文件

 

在我創建的1_modules_custom_counter文件中有一個printOutputVal()方法,它並沒有通過exports或module.exports提供對外公開訪問方法,

如果1_modules_load文件中直接訪問運行會出現什么樣的情況呢?

答案是:TypeError: Object #<Object> has no method 'printOutputVal'

exports和module.exports 區別

    經過上面的例子,通過exports和module.exports對外公開的方法都可以訪問!那既然兩種都能達到效果,但總得有點區別的吧~~~用個例子看看吧!

 

var counter  = 0;     

exports.printNextCount = function (){    
    counter += 2;
    console.log(counter);
}

var isEq = (exports === module.exports);

console.log(isEq);
2_modules_diff_exports.js 文件源碼

下面再新建個2_modules_diff_exports_load.js文件調用一下

var Counter = require('./2_modules_diff_exports');

Counter.printNextCount();
2_modules_diff_exports_load.js 文件源碼

調用后,執行結果如上圖 

我在2_modules_diff_exports_load.js文件中輸出了isEq的值  ( var isEq = (exports === module.exports); ),返回的true 

PS:注意是三個等號,如果不清楚自已查查資料吧!

不用急着下結論,把這兩個JS文件分別改成module.exports對應的代碼

//修改后的2_modules_diff_exports.js源碼如下
var counter  = 0;     

module.exports = function(){    
    counter += 10;
    this.printNextCount = function()
    {
        console.log(counter);    
    }
}

var isEq = (exports === module.exports);

console.log(isEq);
//修改后的2_modules_diff_exports_load.js文件源碼如下
var Counter = require('./2_modules_diff_exports');

var counterObj = new Counter();
counterObj.printNextCount();

調用后,執行結果如上圖 

我在2_modules_diff_exports_load.js文件中輸出了isEq的值  ( var isEq = (exports === module.exports); ),返回的false,這與用先前得到的結果不一致!

PS:不要用Counter.printNextCount();去訪問,你只會得到一個錯誤的提示

 

API提供了解釋

http://nodejs.org/api/modules.html

Note that exports is a reference to module.exports making it suitable for augmentation only. If you are exporting a single item such as a constructor you will want to use module.exports directly instead
exports僅僅是module.exports的一個地址引用。nodejs只會導出module.exports的指向,如果exports指向變了,那就僅僅是exports不在指向module.exports,於是不會再被導出

參考其它理解:

http://www.hacksparrow.com/node-js-exports-vs-module-exports.html

http://zihua.li/2012/03/use-module-exports-or-exports-in-node/

module.exports才是真正的接口,exports只不過是它的一個輔助工具。 最終返回給調用的是module.exports而不是exports。
所有的exports收集到的屬性和方法,都賦值給了Module.exports。當然,這有個前提,就是module.exports本身不具備任何屬性和方法。
如果,module.exports已經具備一些屬性和方法,那么exports收集來的信息將被忽略。

exports和module.exports 覆蓋

 上面也也基本明白了exports和module.exports的關系和區別,但如果同時針對printNextCount()方法存在exports和module.exports,結果如何?

調用結果

從結果可以看出,並沒有報錯,表示可以這么定義,但最終module.exports覆蓋了exports

 

雖然結果不會報錯,如果這么用開發中難免會有一些問題存在,所以

1.最好別分別定義module.exports和exports

2.NodeJs開發者建議導出對象用module.exports,導出多個方法和變量用exports

其它...

   API中還提供了其它的方法,就不細講了,在上面例子的基礎上自已動手一輸出就知道了

 

  module.id

  返回string類型的模塊標識,一般為完全解析后的文件名


  module.filename

  返回一個string類型的完全解析后文件名


  module.loaded

  返回一個bool類型,表示是否加載完成


  module.parent

  返回引用該模塊的模塊


  module.children

  返回該模塊引用的所有模塊對象的數組

 


免責聲明!

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



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