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()