1. 程式人生 > >NodeJS模組和ES6模組系統語法及注意點

NodeJS模組和ES6模組系統語法及注意點

社群模組規範:

1.CommonJS規範
規範實現者:
NodeJS 服務端
Browserify 瀏覽器

2.AMD規範 全稱 非同步模組定義
規範實現者:
RequireJS 瀏覽器

3.CMD規範 通用模組定義
規範實現者:
seaJS 服務端和瀏覽器通用

官方模組規範

1.ESM規範 就是ES6 Module
各瀏覽器和服務端

目前常用的就是瀏覽器端的RequireJS、NodeJS、以及ESM

CommonJS語法分析

module.export

關鍵
1.module.exports實質上是一個物件,最後模組匯出的物件就是這個引用指向的物件

  module.export.key = value
  // eg: 
  module.export.a = 1; 
  // 整體管理匯出,此時exports與module.exports指向斷開,導致exports上的屬性被忽略
  module.export = {
    a:1,
    b:1
  }

2.exports是一個module.export的助手變數,用於就地匯出,兩者預設指向同一物件,即module.exports === exports true

  // 像比較長的程式,寫完所有之後,再去找到需要匯出的變數再移到低端的export.module上逐個新增,是相當麻煩,一般在變數下決定是否匯出
  //eg 
  let fA = function () {

  }
  module.exports.fA = fA
  let fB = function () {

  }
  module.exports.fB = fB

  // exports 簡潔很多
  let fA = function () {

  }
  module.fA = fA
  let fB = function () {

  }
  module.fB = fB

3.在逐個匯出時使用exports,而在匯出一個物件時,使用module.exports,不建議混用,如果需要,可以作一下處理:

  // 在最後匯出時將exports物件和module.exports物件合併
  exports.a = 1
  module.exports = Object.assign({
  b : 1
  },exports)

require

關鍵:
1.模組區分,知道即可
let f = require('url')

  // 核心模組,第三方模組(npm安裝),指定模組名即可
  let f = require ('modulename')
  // 自定義模組,需指定相對或者絕對路徑
  let f = require('absolutePATH/relativeAPTH')

2.查詢時,沒有後綴名的會嘗試新增.js、.json、.node,這裡可以稍微偷個懶

  let f = require('./circle')
  // 等同於
  let f = require('./circle.js')

ESM語法分析:

export var/function/class

關鍵:
1.匯出值和內部值要有對於關係,即

  // error
  export 1

  // error
  let m = 1
  export m

  // correct
  export let m = 1

  // correct
  let m = 1;
  export {m}

直接在宣告時匯出或者用一個{}包裹匯出

2.export default 用於匯出一個預設值,使得使用者可以不需要知道內部匯出變數名稱即可使用
PS: 一個模組只能有一個預設匯出

  export default 等同 export {add as default}
  // 不能接變數宣告語句
  export default let a = 1

普通匯出與預設匯出使用的區別

  // 普通匯出的匯入使用
  export {f}
  import {f} from 'fmod'

  // 預設匯出的匯入使用,可以無需知道匯出模組的內部變數名,任意重新命名
  export default f
  import c from 'fmod'

3.匯出值與模組值是動態繫結的

export let foo = 'bar';
// 500毫秒後,其他模組拿到的foo值會變成bar
setTimeout(() => foo = 'baz', 500);

import用法

關鍵:
1.匯入非預設變數時需要使用{}語法,並且變數要與匯出時變數一致

  // 普通匯出的匯入使用
  export {f}
  import {f} from 'fmod'

2.匯入預設變數時,省略{},並且可以重新命名匯出變數

  // 預設匯出的匯入使用,可以無需知道匯出模組的內部變數名,任意重新命名
  export default f
  import c from 'fmod'

3.可以使用*匯出整體模組

  // circle.js
  export let radius = 1
  export let area = 2*PI*radius
  // main.js
  import * as circle from './circle.js'
  circle.radius
  circle.area

4.可以使用,同時匯出預設匯出和常規匯出

import _,{each, forEach} from 'lodash'

5.多次import同一模組,只會執行一次

6.import可以與require混用,但是其在靜態分析階段執行,也就是會先於require載入,這在要求一定的匯入順序時要注意

export 與 import複合寫法

export { foo, bar } from 'my_module';

// 可以簡單理解為,但是合併寫法等同於沒有在當前模組中匯入my_module,即無法使用
import { foo, bar } from 'my_module';
export { foo, bar };

ESM載入CommmonJS

關鍵:
1.CommonJS模組輸出物件module.exports將會被Node轉換成預設匯出

  // 匯出
  export default module.exports
  // 匯入,類似匯入預設
  import m from './m'

2.此時CommonJS模組變數遵循其規則,不會動態繫結

  module.exports = 123;
  setTimeout(() => module.exports = null,500)
  //500毫秒後,module.exports仍然是123

3.由於CommonJS模組執行時,才會確定輸出的module.exports物件,而ESM在編譯時就要確定介面,匯入時,不允許解構語法

  import {readFile} from 'fs'

解決方案:

  //整體匯入 
  import * as express from 'express'
  const app = express.default()
  
  //預設匯入,更優
  import express from 'express'
  const app = express()