1. 程式人生 > >Module.exports 和 exports

Module.exports 和 exports

Module.exports 和 exports

在node中,沒有全域性作用域,只有模組作用域,外部訪問不到內部,內部也訪問不到外部,那麼模組間如何通訊

  • 當載入一個模組的時候,被載入模組的程式碼在第一次載入的時候會執行一遍

module.exports

  • 被載入模組可以使用 node 提供 的 module.exports 來絕對向外暴露的內容(不設定的話預設為一個空物件) module 在node.js 模組中一般都表示本模組的意思

    require 函式真是實現:

    function require(/* ... */) {
      const module = { exports: {} }; // exports 預設為空物件
      ((module, exports) => {
        // 模組程式碼在這。在這個例子中,定義了一個函式。
        function someFunc() {}
        exports = someFunc;
        // 此時,exports 不再是一個 module.exports 的快捷方式,
        // 且這個模組依然匯出一個空的預設物件。
        module.exports = someFunc;
        // 此時,該模組匯出 someFunc,而不是預設物件。
      })(module, module.exports);
      return module.exports;
    }

 exprot

  • exportmodule.exports 指向的是同一個物件地址

  • 最終 require() 函式返回的是 module.exports 中的資料

    以當 module.exports 屬性被一個新的物件完全替代時 , require 的資料肯定也會變成新值;但是,如果給 export 物件改變地址的話, module.exports不會改變, requrie的值自然也就不會發生變化;可以將 export 想象成 module.exports 的快捷方式

module.exports與exports的區別

每一個node.js執行檔案,都會建立一個module物件,同時,module物件會建立一個叫 exports 的屬性,初始化的值是 { }

module.exports = { }

在模組的結尾,會將 module.exports 返回

return module.exports

說白了,exprots 是 引用的 module.exprots的值,moudule.exprots 被改變的時候 , exprots 不會被改變。 而模組匯出的時候,真正匯出的是 module.exprots, 而不是 exprots

例項解析

同目錄下建立兩個檔案, a.js, 和 b.js

a.js寫入程式碼, 輸出foo來看看b.js匯出的模組到底是什麼

var foo = require('./b')

console.log(foo)
  • b.js 什麼也不寫的情況下,

    { }

    執行a.js 輸出 一個空物件, 這也說明了我們的模組預設匯出一個空物件

  • b.js 程式碼如下

    exports.a = 1
    
    //此時 執行 a.js 輸出 :
    //  { a: 1 }
  • b.js 程式碼如下

    module.exports.a = 2
    
    exports.a = 1
    
    //此時 執行 a.js 輸出 :
    //  { a: 1 }

    兩句語句的操作其實是操作同一塊物件地址,所以以最後的為準 a.js執行輸出為1

  • b.js 程式碼如下

    module.exports = {
      a : 2
    }
    
    exports.a = 1
    
    //此時 執行 a.js 輸出 :
    //  { a: 2 }

    此時執行結果變為 2 為什麼?

    因為第次賦值操作的時候,本質是改變了 moudule.exprots 的地址, 為 module.exports 開闢了一塊新的地址來儲存資料 ,而 exprots 還是 連線著 原來的共享地址。 而模組最後匯出的是 module.exports 這樣應該就能理解其中的原因了吧

  • 來一個複雜的

    exports.a = 'aaa'
    // module.exports = {
    //   a: 'aaa'
    // }  
    module.exports.b = 123
    // module.exports = {
    //   a: 'aaa',
    //   b: 123
    // }  
    
    exports = {
      b: 456
    }
    // 此時 exports 和 module.exprots 斷開聯絡,不再是同一片地址
    
    module.exports.a = 'hahaha'
    // module.exports = {
    //   a: 'hahaha',
    //   b: 123
    // }  
    
    exports.c = 456
    // 斷開聯絡 賦值無法作用與 modul.exports
    
    exports = module.exports
    // 又指向同一片地址
    
    exports.b = 789
    // module.exports = {
    //   a: 'hahaha',
    //   b: 789
    // } 

    最後輸出 { a: 'hahaha', b: 789 }

require

require一般匯入下列三種包

  • 內建核心模組
  • 第三方模組
  • 使用者自己的模組

不可能有任何一個第三方包和核心模組的名字是一樣的

模組查詢機制

  1. 優先快取
  2. 核心模組
  3. 路徑形式的檔案模組
  4. 第三方模組

當 Node 執行 require(A) 時,按下面處理

1. 當 A 是 內建模組

a, 返回該模組

b, 不在執行

2. 當 A 是 './' '/' '../' 開頭的路徑請求

a, 確定 A 所在的父模組, 確定 A 的 絕對路徑

b, 將 A 當成檔案 依次查詢

  • A
  • A.js
  • A.json
  • A.node

只要其中有一個存在,就返回該檔案,不再繼續執行

c, 將 A 當成目錄資料夾, 查詢 A 資料夾下的下列檔案

  • A/package.json
  • A/index.js
  • A/index.json
  • A/index.node

    3. 當 A 屬於第三方模組的時候

    假想當前指令碼檔案 /home/akong/projects/foo.js 執行了 require('bar')

/home/akong/projects/node_modules/bar
/home/akong/node_modules/bar
/home/node_modules/bar
/node_modules/bar

node 會按照上面的順序依次向上級的node_modules搜尋bar

搜尋時,node會先 bar 當成檔名 依次嘗試載入下面這些檔案,只要有一個成功就返回

bar
bar.js
bar.json
bar.node

如果都不成功,就將bar當做資料夾,搜尋下面的檔案

bar/package.json(main欄位)
bar/index.js
bar/index.json
bar/index.node

雜記

  • 在node中,全域性模組的使用不需要載入,而非全域性模組則需要載入。

    process 模組在使用的時候無需通過 require( )來載入該函式,可以直接使用,而 fs 模組不是全域性模組,需要載入來使用 var fs = require('fs')

  • Node 即是單執行緒的,又是非同步非阻塞I/O

  • data 引數的資料型別是一個 buffer 物件 ,裡面儲存的就是一個一個的位元組(理解為字元陣列)
    把buffer物件轉化為字串,用toString方法 預設 utf8

  • 檔案操作的 ./ 相對路徑,相對的是執行 node 命令的路徑

    解決:

    __durbane:表示當前正在執行的 js 檔案所在的目錄

    __filename: 表示當前正在執行的 js 檔案的完整路徑

    兩者都是本地變數,使用時不用載入

    使用路徑拼接的時候我們可以使用node提供的一個path模組,他可以更智慧的識別反斜槓的存在和作業系統的相容性,是我們的程式更簡潔,相容性更好

  • node 錯誤優先規則,在node回撥中,一般都是用err當做第一個回撥引數

  • try-catch 只能捕獲 同步中的錯誤,非同步中的錯誤無法用 trycatch來捕獲,對於非同步操作,要通過判斷錯誤號(err.code)來進行出錯處理

  • 在請求伺服器的時候,請求的url就只是一個標識,無其他作用

  • require 模組載入是同步的

  • 當載入一個模組的時候,被載入模組的程式碼在第一次載入的時候會執行一遍,並快取起來,後續載入的話就不會執行程式碼

  • node.js 遵循了 CommonJS 語法規範

  • 在node中,沒有全域性作用域,只有模組作用域,外部訪問不到內部,內部也訪問不到外部