先來看下官網對module.exports和exports的描述:
The module.exports object is created by the Module system. Sometimes this is not acceptable; many want their module to be an instance of some class. To do this, assign the desired export object to module.exports. Note that assigning the desired object to exports will simply rebind the local exports variable, which is PRobably not what you want to do.
The exports variable is available within a module’s file-level scope, and is assigned the value of module.exports before the module is evaluated.
It allows a shortcut, so that module.exports.f = … can be written more succinctly as exports.f = …. However, be aware that like any variable, if a new value is assigned to exports, it is no longer bound to module.exports
從上邊我們可以得到以下幾點信息: 1. module.exports是由Module系統自動創建。 2. exports是module.exports的引用。 2. exports的作用域僅限所在文件內。 2. export收集到的屬性、方法會賦值給module.exports 3. 通過require得到的是module.exports中的內容,而不是exports的內容。
以上可以看出,exports收集的屬性、方法最后會賦值給module.exports,但是需要注意的是,如果module.exports已經有屬性或方法,那么exports收集的屬性或方法將被忽略,不會被module.exports收集到。
首先,我們先創建兩個js文件:a.js和b.js,代碼分別為: a.js文件內容:
function sayHello() { console.log('hello!');}/*輸出相關信息*/var eq = exports === module.exports;console.log('相等?'+eq);console.log(exports);console.log(module.exports);b.js文件內容:
/*引用文件a*/var a = require('./a.js');在上述代碼中,文件a中定義了sayHello方法,并在文件b中引入了文件a,下面通過示例,來了解下兩者間的差別。
在a.js文件中添加代碼,給exports賦值。
function sayHello() { console.log('hello!');}/*把方法賦值給exports,moudule.exports也會有這方法*/exports.sayHello = sayHello;/*輸出相關信息*/var eq = exports === module.exports;console.log('相等?'+eq);console.log(exports);console.log(module.exports);運行b.js,輸出結果如下:
E:/Projects/Test>node b.js相等?true{ sayHello: [Function: sayHello] }{ sayHello: [Function: sayHello] }從輸出結果上可以看到,exports會把屬性、方法傳遞給module.exports,二者沒有區別。
在a.js文件中添加代碼,給module.exports的屬性賦值。
function sayHello() { console.log('hello!');}module.exports.exports = sayHello;/*輸出相關信息*/var eq = exports === module.exports;console.log('相等?'+eq);console.log(exports);console.log(module.exports);運行b.js,輸出結果如下:
E:/Projects/Test>node b.js相等?true{ sayHello: [Function: sayHello] }{ sayHello: [Function: sayHello] }從輸出結果上可以看到,module.exports和exports指向相同,二者沒有不同。
在a.js文件中添加代碼,給exports賦值。
function sayHello() { console.log('hello!');}/*把一個方法賦值給exports*/exports = sayHello;/*輸出相關信息*/var eq = exports === module.exports;console.log('相等?'+eq);console.log(exports);console.log(module.exports);運行b.js,輸出結果如下:
E:/Projects/Test>node b.js相等?false[Function: sayHello]{}從輸出結果上可以看到,exports沒有把屬性、方法傳遞給module.exports,最終module.exports和exports指向不同,說明二者是有區別的。
在一開始,exports為文件內部的一個變量,和module.exports指向相同,都指向一個空對象{}。而在文件最后,將一個函數賦值給exports時,改變了exports的指向,此時exports指向了該函數,而沒有修改module.exports的指向,導致最后兩者不再指向相同內容。如果想讓兩者指向相同,應這樣寫:module.exports = exports = function say(){…}
下面代碼模擬一個文件被require時,node框架處理modul過程(摘自官網):
function require(...) { var module = { exports: {} }; ((module, exports) => { // Your module code here. In this example, define a function. function some_func() {}; exports = some_func; // At this point, exports is no longer a shortcut to module.exports, and // this module will still export an empty default object. module.exports = some_func; // At this point, the module will now export some_func, instead of the // default object. })(module, module.exports); return module.exports;}在a.js文件中添加代碼,給module.exports賦值。
function sayHello() { console.log('hello!');}module.exports = { say : 'say'};exports.say = 'say exports';/*輸出相關信息*/var eq = exports === module.exports;console.log('相等?'+eq);console.log(exports);console.log(module.exports);運行b.js,輸出結果如下:
E:/Projects/Test>node b.js相等?false{ say: 'say exports' }{ say: 'say' }從輸出結果上可以看到,module.exports和exports指向不相同。原因為module.exports改變了指向,二者指向不再相同,即module.exports已經有屬性或方法,那么exports收集的屬性或方法將被忽略,不會被module.exports收集到。
module.exports和exports之間無論如何賦值,只要分析清楚二者間引用關系,即可知道最后Module導出的對象是誰。 最后,推薦在寫代碼時,只使用module.exports導出相關屬性、方法或對象,避免和exports的混淆。
新聞熱點
疑難解答