跟我學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); //設置增量為10counter.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文件中輸出了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://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
返回該模塊引用的所有模塊對象的數組
推薦閱讀:
※零後端基礎想搭建一個高可用的node服務,需要學習什麼,有什麼比較好的教程或者開源練手項目么?
※別人家的node都是100萬級別的,我的怎麼5000+伺服器就開始主動斷開連接了?
※nodejs工程師一般工作內容是什麼?
TAG:Nodejs |