ES Module的基本使用

ES Module

本博主會(huì)持續(xù)更新各種前端的技術(shù),如果各位道友喜歡漾脂,可以關(guān)注假颇、收藏、點(diǎn)贊下本博主的文章骨稿。

ES Module 基本特性

  • ESM 自動(dòng)采用嚴(yán)格模式笨鸡,忽略 'use strict'
  • 每個(gè) ES Module 都是運(yùn)行在單獨(dú)的私有作用域中
  • ESM 是通過(guò) CORS 的方式請(qǐng)求外部 JS 模塊的
  • ESM 的 script 標(biāo)簽會(huì)延遲執(zhí)行腳本(瀏覽器頁(yè)面渲染后執(zhí)行)

export

在創(chuàng)建 JavaScript 模塊時(shí),export 語(yǔ)句用于從模塊中導(dǎo)出實(shí)時(shí)綁定的函數(shù)坦冠、對(duì)象或原始值形耗,以便其他程序可以通過(guò) import 語(yǔ)句使用它們。被導(dǎo)出的綁定值依然可以在本地進(jìn)行修改辙浑。在使用 import 進(jìn)行導(dǎo)入時(shí)激涤,這些綁定值只能被導(dǎo)入模塊所讀取,但在 export 導(dǎo)出模塊中對(duì)這些綁定值進(jìn)行修改判呕,所修改的值也會(huì)實(shí)時(shí)地更新倦踢。

無(wú)論您是否聲明,導(dǎo)出的模塊都處于嚴(yán)格模式佛玄。 export 語(yǔ)句不能用在嵌入式腳本中硼一。

// 導(dǎo)出單個(gè)特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}

// 導(dǎo)出列表
export { name1, name2, …, nameN };

// 重命名導(dǎo)出
export { variable1 as name1, variable2 as name2, …, nameN };

// 解構(gòu)導(dǎo)出并重命名
export const { name1, name2: bar } = o;

// 默認(rèn)導(dǎo)出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

// 合并 modules
export * from …; // does not set the default export
export * as name1 from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;

import

靜態(tài)的 import 語(yǔ)句用于導(dǎo)入由另一個(gè)模塊導(dǎo)出的綁定。無(wú)論是否聲明了 strict mode 梦抢,導(dǎo)入的模塊都運(yùn)行在嚴(yán)格模式下般贼。在瀏覽器中,import 語(yǔ)句只能在聲明了 type="module" 的 script 的標(biāo)簽中使用奥吩。

此外哼蛆,還有一個(gè)類(lèi)似函數(shù)的動(dòng)態(tài) import(),它不需要依賴(lài) type="module" 的 script 標(biāo)簽霞赫。

在 script 標(biāo)簽中使用 nomodule 屬性腮介,可以確保向后兼容。

在您希望按照一定的條件或者按需加載模塊的時(shí)候端衰,動(dòng)態(tài) import() 是非常有用的叠洗。而靜態(tài)型的 import 是初始化加載依賴(lài)項(xiàng)的最優(yōu)選擇甘改,使用靜態(tài) import 更容易從代碼靜態(tài)分析工具和 tree shaking 中受益。

// 導(dǎo)入整個(gè)模塊的內(nèi)容
import * as myModule from '/modules/my-module.js';

// 導(dǎo)入單個(gè)接口
import {myExport} from '/modules/my-module.js';
// 導(dǎo)入多個(gè)接口

import {foo, bar} from '/modules/my-module.js';

// 導(dǎo)入帶有別名的接口
import {reallyReallyLongModuleExportName as shortName} from '/modules/my-module.js';

// 導(dǎo)入時(shí)重命名多個(gè)接口
import {
  reallyReallyLongModuleMemberName as shortName,
  anotherLongModuleName as short
} from '/modules/my-module.js';

// 僅為副作用而導(dǎo)入一個(gè)模塊
// 整個(gè)模塊僅為副作用(中性詞灭抑,無(wú)貶義含義)而導(dǎo)入十艾,而不導(dǎo)入模塊中的任何內(nèi)容(接口)。 這將運(yùn)行模塊中的全局代碼, 但實(shí)際上不導(dǎo)入任何值腾节。
import '/modules/my-module.js';

// 導(dǎo)入默認(rèn)值
import myDefault from '/modules/my-module.js';
import myDefault, * as myModule from '/modules/my-module.js';
// myModule used as a namespace
import myDefault, {foo, bar} from '/modules/my-module.js';
// specific, named imports

// 動(dòng)態(tài)import
import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });
let module = await import('/modules/my-module.js');

node 環(huán)境下

es module 使用

index.mjs

// 第一忘嫉,將文件的擴(kuò)展名由 .js 改為 .mjs;
// 第二案腺,啟動(dòng)時(shí)需要額外添加 `--experimental-modules` 參數(shù)庆冕;

import { foo, bar } from './module.mjs';

console.log(foo, bar);

// 此時(shí)我們也可以通過(guò) esm 加載內(nèi)置模塊了
import fs from 'fs';
fs.writeFileSync('./foo.txt', 'es module working');

// 也可以直接提取模塊內(nèi)的成員,內(nèi)置模塊兼容了 ESM 的提取成員方式
import { writeFileSync } from 'fs';
writeFileSync('./bar.txt', 'es module working');

// 對(duì)于第三方的 NPM 模塊也可以通過(guò) esm 加載
import _ from 'lodash';
_.camelCase('ES Module');

// 不支持劈榨,因?yàn)榈谌侥K都是導(dǎo)出默認(rèn)成員
// import { camelCase } from 'lodash'
// console.log(camelCase('ES Module'))

與 CommonJS 交互

  • ES Module 中可以導(dǎo)入 CommonJS 模塊
  • CommonJS 中不能導(dǎo)入 ES Module 模塊
  • CommonJS 始終只會(huì)導(dǎo)出一個(gè)默認(rèn)成員
  • 注意 import 不是解構(gòu)導(dǎo)出對(duì)象

commonjs.js

// CommonJS 模塊始終只會(huì)導(dǎo)出一個(gè)默認(rèn)成員

// module.exports = {
//   foo: 'commonjs exports value'
// }

// exports.foo = 'commonjs exports value'

// 不能在 CommonJS 模塊中通過(guò) require 載入 ES Module

// const mod = require('./es-module.mjs')
// console.log(mod)

es-module.mjs

// ES Module 中可以導(dǎo)入 CommonJS 模塊

// import mod from './commonjs.js'
// console.log(mod)

// 不能直接提取成員访递,注意 import 不是解構(gòu)導(dǎo)出對(duì)象

// import { foo } from './commonjs.js'
// console.log(foo)

// export const foo = 'es module export value'

與 CommonJS 的差異

esm.mjs

// ESM 中沒(méi)有模塊全局成員了

// // 加載模塊函數(shù)
// console.log(require)

// // 模塊對(duì)象
// console.log(module)

// // 導(dǎo)出對(duì)象別名
// console.log(exports)

// // 當(dāng)前文件的絕對(duì)路徑
// console.log(__filename)

// // 當(dāng)前文件所在目錄
// console.log(__dirname)

// -------------

// require, module, exports 自然是通過(guò) import 和 export 代替

// __filename 和 __dirname 通過(guò) import 對(duì)象的 meta 屬性獲取
// const currentUrl = import.meta.url
// console.log(currentUrl)

// 通過(guò) url 模塊的 fileURLToPath 方法轉(zhuǎn)換為路徑
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__filename);
console.log(__dirname);

Node v12 之后的版本,可以通過(guò)package.json中添加type字段為module鞋既,將默認(rèn)模塊系統(tǒng)修改為ES Module力九,此時(shí)就不需要修改文件擴(kuò)展名為.mjs

如果需要在type=module的情況下繼續(xù)使用CommonJS耍铜,需要將文件擴(kuò)展名修改為.cjs

對(duì)于早期的 Node.js 版本邑闺,可以使用 Babel 實(shí)現(xiàn) ES Module 的兼容

// 配置:第一種方式
{
  "plugins": [
    "@babel/plugin-transform-modules-commonjs"
  ]
}
// 配置:第二種方式(合集)
{
"presets":["@babel/preset-env"]
}

具體 Module 的語(yǔ)法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市棕兼,隨后出現(xiàn)的幾起案子陡舅,更是在濱河造成了極大的恐慌,老刑警劉巖伴挚,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靶衍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡茎芋,警方通過(guò)查閱死者的電腦和手機(jī)颅眶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)田弥,“玉大人涛酗,你說(shuō)我怎么就攤上這事⊥迪茫” “怎么了商叹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)只泼。 經(jīng)常有香客問(wèn)我剖笙,道長(zhǎng),這世上最難降的妖魔是什么请唱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任弥咪,我火速辦了婚禮过蹂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘聚至。我一直安慰自己榴啸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布晚岭。 她就那樣靜靜地躺著鸥印,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坦报。 梳的紋絲不亂的頭發(fā)上库说,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音片择,去河邊找鬼潜的。 笑死,一個(gè)胖子當(dāng)著我的面吹牛字管,可吹牛的內(nèi)容都是我干的啰挪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼嘲叔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼亡呵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起硫戈,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤锰什,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后丁逝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體汁胆,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年霜幼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嫩码。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罪既,死狀恐怖铸题,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萝衩,我是刑警寧澤回挽,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站猩谊,受9級(jí)特大地震影響千劈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜牌捷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一墙牌、第九天 我趴在偏房一處隱蔽的房頂上張望涡驮。 院中可真熱鬧,春花似錦喜滨、人聲如沸捉捅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)棒口。三九已至,卻和暖如春辜膝,著一層夾襖步出監(jiān)牢的瞬間无牵,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工厂抖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茎毁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓忱辅,卻偏偏與公主長(zhǎng)得像七蜘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子墙懂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359