exports 和 module.exports 的區別

我理解的exports 和 module.exports 的區別,歡迎大家吐槽~

爲了更好的理解 exports module.exports 的關係,我們先來補點 js 基礎。示例:

app.js

var a = {name: 'nswbmw 1'};
var b = a;

console.log(a);
console.log(b);

b.name = 'nswbmw 2';
console.log(a);
console.log(b);

var b = {name: 'nswbmw 3'};
console.log(a);
console.log(b);

運行 app.js 結果爲:

D:\>node app
{ name: 'nswbmw 1' }
{ name: 'nswbmw 1' }
{ name: 'nswbmw 2' }
{ name: 'nswbmw 2' }
{ name: 'nswbmw 2' }
{ name: 'nswbmw 3' }

D:\>

解釋一下:a 是一個對象,b 是對 a 的引用,即 a 和 b 指向同一個對象,即 a 和 b 指向同一塊內存地址,所以前兩個輸出一樣。當對 b 作修改時,即 a 和 b 指向同一塊內存地址的內容發生了改變,所以 a 也會體現出來,所以第三四個輸出一樣。當對 b 完全覆蓋時,b 就指向了一塊新的內存地址(並沒有對原先的內存塊作修改),a 還是指向原來的內存塊,即 a 和 b 不再指向同一塊內存,也就是說此時 a 和 b 已毫無關係,所以最後兩個輸出不一樣。

明白了上述例子後,我們進入正題。我們只需知道三點即可知道 exports module.exports 的區別了:

  1. exports 是指向的 module.exports 的引用
  2. module.exports 初始值爲一個空對象 {},所以 exports 初始值也是 {}
  3. require() 返回的是 module.exports 而不是 exports

所以:

  • 我們通過

      var name = 'nswbmw';
      exports.name = name;
      exports.sayName = function() {
        console.log(name);
      }

    exports 賦值其實是給 module.exports 這個空對象添加了兩個屬性而已,上面的代碼相當於:

      var name = 'nswbmw';
      module.exports.name = name;
      module.exports.sayName = function() {
        console.log(name);
      }
  • 我們通常這樣使用 exports module.exports

    一個簡單的例子,計算圓的面積:

    使用 exports

    app.js

      var circle = require('./circle');
      console.log(circle.area(4));

    circle.js

      exports.area = function(r) {
        return r * r * Math.PI;
      }

    使用 module.exports

    app.js

      var area = require('./area');
      console.log(area(4));

    area.js

      module.exports = function(r) {
        return r * r * Math.PI;
      }

    上面兩個例子輸出是一樣的。你也許會問,爲什麼不這樣寫呢?

    app.js

      var area = require('./area');
      console.log(area(4));

    area.js

      exports = function(r) {
        return r * r * Math.PI;
      }

    運行上面的例子會報錯。這是因爲,前面的例子中通過給 exports 添加屬性,只是對 exports 指向的內存做了修改,而

      exports = function(r) {
        return r * r * Math.PI;
      }

    其實是對 exports 進行了覆蓋,也就是說 exports 指向了一塊新的內存(內容爲一個計算圓面積的函數),也就是說 exports module.exports 不再指向同一塊內存,也就是說此時 exports module.exports 毫無聯繫,也就是說 module.exports 指向的那塊內存並沒有做任何改變,仍然爲一個空對象 {} ,也就是說 area.js 導出了一個空對象,所以我們在 app.js 中調用 area(4) 會報 TypeError: object is not a function 的錯誤。

    所以,一句話做個總結:當我們想讓模塊導出的是一個對象時, exports module.exports 均可使用(但 exports 也不能重新覆蓋爲一個新的對象),而當我們想導出非對象接口時,就必須也只能覆蓋 module.exports

  • 我們經常看到這樣的用寫法:

      exports = module.exports = somethings

    上面的代碼等價於

      module.exports = somethings
      exports = module.exports

    原因也很簡單, module.exports = somethings 是對 module.exports 進行了覆蓋,此時 module.exports exports 的關係斷裂,module.exports 指向了新的內存塊,而 exports 還是指向原來的內存塊,爲了讓 module.exports exports 還是指向同一塊內存或者說指向同一個 “對象”,所以我們就 exports = module.exports

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章