圖文揭秘Node.js中exports和module.exports

概述

首先我們得先擺出兩條不變的真理:

  1. exports一開始是指向module.exports的蒲祈;
  2. 通過require得到的是module.exports中的內(nèi)容,而不是exports的內(nèi)容;

詳解

exports和module這兩個(gè)對(duì)象是所有Node.js類型的文件中都默認(rèn)隱式存在的,比如我們新建一個(gè)test.js文件:

console.log(exports);
console.log(module);

在終端運(yùn)行:

[qifuguang@Mac~/nodejs/learnModule]$ node test.js
{}
Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/Users/qifuguang/nodejs/learnModule/test.js',
  loaded: false,
  children: [],
  paths:
   [ '/Users/qifuguang/nodejs/learnModule/node_modules',
     '/Users/qifuguang/nodejs/node_modules',
     '/Users/qifuguang/node_modules',
     '/Users/node_modules',
     '/node_modules' ] }

可以看到肺缕,test.js文件中并未聲明exports和module對(duì)象,但是它們確實(shí)存在。并且可以看到同木,exports的初始值是{}浮梢,而module的初始值有一大串屬性,其中還包含一個(gè)exports屬性泉手,它的初始值也是{}黔寇。

實(shí)際上,一開始exports就是指向module.exports的斩萌,引用關(guān)系如下圖:



請(qǐng)牢記這個(gè)引用圖,之后的分析都依靠這個(gè)圖屏轰。

我們?cè)倥e個(gè)例子颊郎,創(chuàng)建如下的my_module.js文件:

exports.sayHello = function() {
    console.log('Hello world!');
}

再在同一個(gè)目錄下創(chuàng)建app.js文件:

myModule = require('./my_module');
myModule.sayHello()

在終端運(yùn)行app.js:

[qifuguang@Mac~/nodejs/learnModule]$ node app.js
Hello world!

現(xiàn)在我們分析一下為什么會(huì)有這樣的輸出結(jié)果:
在app.js文件中我們使用require語句從my_module.js模塊中得到了module.exports,這里的module.exports的內(nèi)容是什么呢霎苗?

在my_module.js文件中我們?cè)趀xports的基礎(chǔ)上為它添加了一個(gè)屬性sayHello姆吭,這個(gè)屬性的值是一個(gè)函數(shù),并且因?yàn)槌跏紩r(shí)唁盏,exports指向的是module.exports内狸,他倆共享同一塊內(nèi)存,所以這個(gè)操作后厘擂,module.exports變成了這樣:



所以昆淡,app.js文件中的myModule變量的值為:

{
    sayHello: function() {console.log('Hello world');}
}

于是,很自然地刽严,我們可以使用myModule.sayHello調(diào)用它對(duì)應(yīng)的函數(shù)昂灵,輸出熟悉的Hello world字符串。

再舉個(gè)例子舞萄,我們將my_module.js文件修改為如下內(nèi)容:

exports = {
    sayHello: function() {console.log('Hello world!');}
}

然后將app.js文件修改為如下內(nèi)容:

myModule = require('./my_module');

console.log('module.exports:');
console.log(module.exports);

myModule.sayHello()

然后一樣在終端運(yùn)行:

[qifuguang@Mac~/nodejs/learnModule]$ node app.js
module.exports:
{}
/Users/qifuguang/nodejs/learnModule/app.js:6
myModule.sayHello()
         ^

TypeError: myModule.sayHello is not a function
    at Object.<anonymous> (/Users/qifuguang/nodejs/learnModule/app.js:6:10)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:136:18)
    at node.js:963:3

可以看到眨补,報(bào)錯(cuò)了,報(bào)錯(cuò)了倒脓,報(bào)錯(cuò)了撑螺!

分析一下原因:
my_module.js文件中將exports重新賦值為一個(gè)新的對(duì)象,這就相當(dāng)于Java中的

Object newObje = new Object();

一樣崎弃,這個(gè)時(shí)候exports將會(huì)自己分配一塊新的內(nèi)存甘晤,而不再指向module.exports了,所以這個(gè)時(shí)候exports和module.exports徹底斷絕關(guān)系吊履,無論你怎么蹂躪(操作)exports對(duì)象安皱,都與module.exports無關(guān)了。

所以艇炎,my_module.js文件中為exports對(duì)象重新賦值之后酌伊,exports和module.exports的狀態(tài)是這樣的:


從輸出中也可以看到,此時(shí)的module.exports={},所以肯定找不到sayHello函數(shù)居砖,那必然報(bào)錯(cuò)虹脯!

其他的我也不多說了,根據(jù)這兩個(gè)例子與這兩幅圖奏候,我相信更多的情況大家都會(huì)自己分析了循集。

聲明

本文首發(fā)于個(gè)人技術(shù)博客,轉(zhuǎn)載請(qǐng)注明出處蔗草,本文鏈接:http://qifuguang.me/2015/11/11/揭秘Node-js中exports和module-exports/

如果你喜歡我的文章咒彤,請(qǐng)關(guān)注我的微信訂閱號(hào):“機(jī)智的程序猿”,更多精彩咒精,盡在其中:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末镶柱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子模叙,更是在濱河造成了極大的恐慌歇拆,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件范咨,死亡現(xiàn)場(chǎng)離奇詭異故觅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)渠啊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門输吏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昭抒,你說我怎么就攤上這事评也。” “怎么了灭返?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵盗迟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我熙含,道長(zhǎng)罚缕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任怎静,我火速辦了婚禮邮弹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚓聘。我一直安慰自己腌乡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布夜牡。 她就那樣靜靜地躺著与纽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上急迂,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天影所,我揣著相機(jī)與錄音,去河邊找鬼僚碎。 笑死猴娩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勺阐。 我是一名探鬼主播卷中,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼渊抽!你這毒婦竟也來了仓坞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤腰吟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后徙瓶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毛雇,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年侦镇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灵疮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡壳繁,死狀恐怖震捣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闹炉,我是刑警寧澤蒿赢,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站渣触,受9級(jí)特大地震影響羡棵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嗅钻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一皂冰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧养篓,春花似錦秃流、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春峻贮,著一層夾襖步出監(jiān)牢的瞬間席怪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工纤控, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挂捻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓船万,卻偏偏與公主長(zhǎng)得像刻撒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耿导,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容