概述
首先我們得先擺出兩條不變的真理:
- exports一開(kāi)始是指向module.exports的;
- 通過(guò)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í)際上,一開(kāi)始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語(yǔ)句從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)系,無(wú)論你怎么蹂躪(操作)exports對(duì)象,都與module.exports無(wú)關(guān)了。
所以,my_module.js文件中為exports對(duì)象重新賦值之后,exports和module.exports的狀態(tài)是這樣的:
從輸出中也可以看到,此時(shí)的module.exports={},所以肯定找不到sayHello函數(shù),那必然報(bào)錯(cuò)!
其他的我也不多說(shuō)了,根據(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ī)智的程序猿”,更多精彩,盡在其中: