概述
首先我們得先擺出兩條不變的真理:
- exports一開始是指向module.exports的蒲祈;
- 通過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ī)智的程序猿”,更多精彩咒精,盡在其中: