跟我學(xué)Nodejs(三)--- Node.js模塊
簡(jiǎn)介及資料
通過(guò)Node.js的官方API可以看到Node.js本身提供了很多核心模塊 http://nodejs.org/api/ ,這些核心模塊被編譯成二進(jìn)制文件,可以require('模塊名')去獲取;核心模塊具有最高的加載優(yōu)先級(jí)(有模塊與核心模塊同名時(shí)會(huì)體現(xiàn))
(本次主要說(shuō)自定義模塊)
Node.js還有一類(lèi)模塊為文件模塊,可以是JavaScript代碼文件(.js作為文件后綴)、也可以是JSON格式文本文件(.json作為文件后綴)、還可以是編輯過(guò)的C/C++文件(.node作為文件后綴);
文件模塊訪(fǎng)問(wèn)方式通過(guò)require('/文件名.后綴') require('./文件名.后綴') requrie('../文件名.后綴') 去訪(fǎng)問(wèn),文件后綴可以省略;以"/"開(kāi)頭是以絕對(duì)路徑去加載,以"./"開(kāi)頭和以"../"開(kāi)頭表示以相對(duì)路徑加載,而以"./"開(kāi)頭表示同級(jí)目錄下文件,
前面提到文件后綴可以省略,Nodejs嘗試加載的優(yōu)先級(jí) js文件 > json文件 > node文件
創(chuàng)建一個(gè)自定義模塊
以一個(gè)計(jì)數(shù)器為例
var outputVal = 0; //輸出值
var increment = 1; //增量
/* 設(shè)置輸出值 */
function seOutputVal (val) {
outputVal = val;
}
/* 設(shè)置增量 */
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;
自定義模塊 示例源碼
示例中重點(diǎn)在于exports和module.exports;提供了外部訪(fǎng)問(wèn)的接口,下面調(diào)用一下看看效果吧
調(diào)用自定義模塊
/*
一個(gè)Node.js文件就是一個(gè)模塊,這個(gè)文件可能是Javascript代碼、JSON或者編譯過(guò)的C/C++擴(kuò)展。
重要的兩個(gè)對(duì)象:
require是從外部獲取模塊
exports是把模塊接口公開(kāi)
*/
var counter = require('./1_modules_custom_counter');
console.log('第一次調(diào)用模塊[1_modules_custom_counter]');
counter.seOutputVal(10); //設(shè)置從10開(kāi)始計(jì)數(shù)
counter.setIncrement (10); //設(shè)置增量為10
counter.printNextCount();
counter.printNextCount();
counter.printNextCount();
counter.printNextCount();
/*
require多次調(diào)用同一模塊不會(huì)重復(fù)加載
*/
var counter = require('./1_modules_custom_counter');
console.log('第二次調(diào)用模塊[1_modules_custom_counter]');
counter.printNextCount();
自定義模式調(diào)用 源碼
運(yùn)行可以發(fā)現(xiàn)通過(guò)exports和module.exports對(duì)外公開(kāi)的方法都可以訪(fǎng)問(wèn)!
示例中可以看到,我兩次通過(guò)require('./1_modules_custom_counter')獲取模塊,但是第二次引用后調(diào)用printNextCount()方法確從60開(kāi)始~~~
原因是node.js通過(guò)requirerequire多次調(diào)用同一模塊不會(huì)重復(fù)加載,Node.js會(huì)根據(jù)文件名緩存所有加載過(guò)的文件模塊,所以不會(huì)重新加載了
注意:通過(guò)文件名緩存是指實(shí)際文件名,并不會(huì)因?yàn)閭魅氲穆窂叫问讲灰粯佣J(rèn)會(huì)是不同的文件
在我創(chuàng)建的1_modules_custom_counter文件中有一個(gè)printOutputVal()方法,它并沒(méi)有通過(guò)exports或module.exports提供對(duì)外公開(kāi)訪(fǎng)問(wèn)方法,
如果1_modules_load文件中直接訪(fǎng)問(wèn)運(yùn)行會(huì)出現(xiàn)什么樣的情況呢?
答案是:TypeError: Object #<Object> has no method 'printOutputVal'
exports和module.exports 區(qū)別
經(jīng)過(guò)上面的例子,通過(guò)exports和module.exports對(duì)外公開(kāi)的方法都可以訪(fǎng)問(wèn)!那既然兩種都能達(dá)到效果,但總得有點(diǎn)區(qū)別的吧~~~用個(gè)例子看看吧!
var counter = 0;
exports.printNextCount = function (){
counter += 2;
console.log(counter);
}
var isEq = (exports === module.exports);
console.log(isEq);
2_modules_diff_exports.js 文件源碼
下面再新建個(gè)2_modules_diff_exports_load.js文件調(diào)用一下
var Counter = require('./2_modules_diff_exports');
Counter.printNextCount();
調(diào)用后,執(zhí)行結(jié)果如上圖
我在2_modules_diff_exports_load.js文件中輸出了isEq的值 ( var isEq = (exports === module.exports); ),返回的true
PS:注意是三個(gè)等號(hào),如果不清楚自已查查資料吧!
不用急著下結(jié)論,把這兩個(gè)JS文件分別改成module.exports對(duì)應(yīng)的代碼
//修改后的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();
調(diào)用后,執(zhí)行結(jié)果如上圖
我在2_modules_diff_exports_load.js文件中輸出了isEq的值 ( var isEq = (exports === module.exports); ),返回的false,這與用先前得到的結(jié)果不一致!
PS:不要用Counter.printNextCount();去訪(fǎng)問(wèn),你只會(huì)得到一個(gè)錯(cuò)誤的提示
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的一個(gè)地址引用。nodejs只會(huì)導(dǎo)出module.exports的指向,如果exports指向變了,那就僅僅是exports不在指向module.exports,于是不會(huì)再被導(dǎo)出
參考其它理解:
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只不過(guò)是它的一個(gè)輔助工具。 最終返回給調(diào)用的是module.exports而不是exports。
所有的exports收集到的屬性和方法,都賦值給了Module.exports。當(dāng)然,這有個(gè)前提,就是module.exports本身不具備任何屬性和方法。
如果,module.exports已經(jīng)具備一些屬性和方法,那么exports收集來(lái)的信息將被忽略。
exports和module.exports 覆蓋
上面也也基本明白了exports和module.exports的關(guān)系和區(qū)別,但如果同時(shí)針對(duì)printNextCount()方法存在exports和module.exports,結(jié)果如何?
調(diào)用結(jié)果
從結(jié)果可以看出,并沒(méi)有報(bào)錯(cuò),表示可以這么定義,但最終module.exports覆蓋了exports
雖然結(jié)果不會(huì)報(bào)錯(cuò),如果這么用開(kāi)發(fā)中難免會(huì)有一些問(wèn)題存在,所以
1.最好別分別定義module.exports和exports
2.NodeJs開(kāi)發(fā)者建議導(dǎo)出對(duì)象用module.exports,導(dǎo)出多個(gè)方法和變量用exports
其它...
API中還提供了其它的方法,就不細(xì)講了,在上面例子的基礎(chǔ)上自已動(dòng)手一輸出就知道了
module.id
返回string類(lèi)型的模塊標(biāo)識(shí),一般為完全解析后的文件名
module.filename
返回一個(gè)string類(lèi)型的完全解析后文件名
module.loaded
返回一個(gè)bool類(lèi)型,表示是否加載完成
module.parent
返回引用該模塊的模塊
module.children
返回該模塊引用的所有模塊對(duì)象的數(shù)組
相關(guān)文章
Bootstrap實(shí)現(xiàn)默認(rèn)導(dǎo)航欄效果
這篇文章主要介紹了Bootstrap實(shí)現(xiàn)默認(rèn)導(dǎo)航欄效果,導(dǎo)航欄是一個(gè)很好的功能,是Bootstrap網(wǎng)站的一個(gè)突出特點(diǎn),本文帶領(lǐng)大家學(xué)習(xí)實(shí)現(xiàn)Bootstrap導(dǎo)航欄,需要的朋友可以參考下2015-12-12JAVASCRIPT代碼編寫(xiě)俄羅斯方塊網(wǎng)頁(yè)版
俄羅斯方塊方塊是小時(shí)候的一個(gè)回憶,從最開(kāi)始的掌上的黑白游戲機(jī),到電視游戲機(jī),到電腦,無(wú)不有它的痕跡,今天我們來(lái)一起重溫它的一種實(shí)現(xiàn)方法,也算是整理一下我的思路吧,感興趣的小伙伴一起學(xué)習(xí)吧2015-11-11關(guān)于IE、Firefox、Opera頁(yè)面呈現(xiàn)異同 寫(xiě)腳本很痛苦
關(guān)于IE、Firefox、Opera頁(yè)面呈現(xiàn)異同 寫(xiě)腳本很痛苦,對(duì)于多瀏覽器的兼容性,需要注意。2009-08-08字節(jié)跳動(dòng)面試之如何用JS實(shí)現(xiàn)Ajax并發(fā)請(qǐng)求控制
這篇文章主要給大家介紹了關(guān)于字節(jié)跳動(dòng)面試之如何用JS實(shí)現(xiàn)Ajax并發(fā)請(qǐng)求控制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05JS實(shí)現(xiàn)的自定義右鍵菜單實(shí)例二則
這篇文章主要介紹了JS實(shí)現(xiàn)的自定義右鍵菜單,以?xún)蓜t實(shí)例形式分析了javascript自定義右鍵菜單效果的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09基于JavaScript實(shí)現(xiàn)自定義滾動(dòng)條
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)自定義滾動(dòng)條,可以直接使用的滾動(dòng)條,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01JS+CSS實(shí)現(xiàn)DIV層的展開(kāi)、收縮效果
這篇文章主要介紹了JS+CSS實(shí)現(xiàn)DIV層的展開(kāi)、收縮效果,以?xún)蓚€(gè)完整實(shí)例介紹了JS控制DIV層的展開(kāi)、收縮效果,感興趣的小伙伴們可以參考一下2016-01-01javascript 控制 html元素 顯示/隱藏實(shí)現(xiàn)代碼
javascript 控制 html元素 顯示/隱藏,下面是一些逐步的實(shí)現(xiàn)原理。2009-09-09