前言
ES modules 是原生 JavaScript 提供的模塊功能看锉,逐漸被更多的瀏覽器開(kāi)始支持
入門(mén)篇
先了解下基礎(chǔ)用法赵刑。
html 文件中使用 ES modules 語(yǔ)法執(zhí)行 js
在 script 標(biāo)簽中 設(shè)置 type = module,瀏覽器就會(huì)以 ES modules 的標(biāo)準(zhǔn)去執(zhí)行 script 標(biāo)簽中的 JavaScript 代碼荚虚。默認(rèn)情況下洼滚,代碼是以嚴(yán)格模式執(zhí)行的歪脏。
<script type="module">
console.log('this is es module')
</script>
私有作用域
每一個(gè)設(shè)置 type=module 的標(biāo)簽內(nèi)都會(huì)形成一個(gè)私有作用域。作用域之間的變量不能直接共享技扼。
<script type="module">
var a = 1
console.log(a)
</script>
<script type="module">
console.log(a)
</script>
第 1 組 script 中的代碼正常輸出變量 a 的值伍玖,第 2 段會(huì)報(bào)以下錯(cuò)誤:a is not defined。
外鏈 JS 文件加載
ES modules 會(huì)以 CORS 方式加載外部 js 文件剿吻。提供 js 文件的服務(wù)器需要設(shè)置 CORS 后窍箍,ES modules 的 script 標(biāo)簽才能正常加載文件。
<script type="module" src="https://unpkg.com/jquery@3.6.0/dist/jquery.js"></script> //第一個(gè)文件服務(wù)器配置了CORS
<script type="module" src="https://abc.com/jquery@3.6.0/dist/jquery.js"></script> //第二個(gè)沒(méi)有配置
結(jié)果:第 1 組 script 標(biāo)簽加載成功丽旅,第 2 組加載失敗椰棘。
延遲執(zhí)行,作用與 defer 一致榄笙。
未設(shè)置 type = module 前邪狞,會(huì)先執(zhí)行完 01_demo.js 的代碼。p 標(biāo)簽的渲染會(huì)被阻塞办斑。
設(shè)置 type = module 后外恕,p 標(biāo)簽的渲染不會(huì)被阻塞。
<script src="./01_demo.js" type="module"></script>
<p>測(cè)試</p>
導(dǎo)出
導(dǎo)出方式
// module.js - 單獨(dú)導(dǎo)出
export var name = "foo module";
export class A {}
export function bar() {}
// 統(tǒng)一導(dǎo)出
var name = "foo module";
class A {}
function bar() {}
export { name, A, bar }
// app.js - 導(dǎo)入
import { name } from "./module.js";
console.log(name);
導(dǎo)出重命名
const age = 25;
export { age as Age };
默認(rèn)模塊導(dǎo)出,導(dǎo)入時(shí)也要重命名
const age = 25;
export { age as default };
export default age;
import { default as Age } from './module.js'
import Age from './module.js'
console.log(Age)
注意事項(xiàng):
1.導(dǎo)出時(shí)乡翅,export 后面不是字面量對(duì)象鳞疲。import 后面也不是對(duì)象解構(gòu)。
2.export default { name, age } 是等價(jià)于導(dǎo)出一個(gè)對(duì)象蠕蚜,export { a, b, c } 則是固定用法尚洽。
3.進(jìn)行導(dǎo)入操作時(shí),導(dǎo)入的是同一份引用靶累,是引用關(guān)系腺毫,并非值,這一點(diǎn)與 common.js 不一樣挣柬。在導(dǎo)入之后潮酒,不能對(duì)導(dǎo)入變量進(jìn)行修改,它是一個(gè)只讀的關(guān)系邪蛔。
導(dǎo)入
1.導(dǎo)入語(yǔ)句中急黎,需要指定完整路徑,不能忽略文件后綴名(但是現(xiàn)有第三包,或者其也是支持不寫(xiě)文件后綴名)勃教。而 common js 是支持忽略文件后綴名淤击。
2.路徑必須以 / 開(kāi)頭。導(dǎo)入路徑支持使用 cdn url 外鏈 js 文件的形式故源。
3.以下導(dǎo)入方式等價(jià)于執(zhí)行導(dǎo)入文件中的 js 代碼污抬。
import {} from './module.js'
import './module.js'
4.將模塊中所有內(nèi)容一次性導(dǎo)入,通過(guò)對(duì)象.變量方式訪(fǎng)問(wèn)绳军。
import * as xxx from './module.js'
5.動(dòng)態(tài)導(dǎo)入,import() 等價(jià)于函數(shù)調(diào)用,非函數(shù)調(diào)用形式只能置于頂層印机。
import('./module.js').then(module => {
console.log(module)
})
6.默認(rèn)成員和具名成員導(dǎo)入。
import { name, age, default as title } from './module.js'
import title, { name, age } froom './module.js'
導(dǎo)出導(dǎo)入成員
一種代碼組織方式删铃,將散落模塊組織成新模塊耳贬。
// components/button.js
export const Button = "Button component";
// components/radio.js
export const Radio = "Radio component";
// components/index.js
import { Button } from "./button.js";
import { Radio } from "./radio.js";
export { Button, Radio };
// app.js
import { Button, Radio } from "./component/index.js";
console.log(Button);
console.log(Radio);
Polyfill 篇
ES modules 是 ES6 推出的新語(yǔ)法特性,在低版本瀏覽器上需要通過(guò) Polyfill 方式去解決兼容性問(wèn)題.
script 添加 nomodule 設(shè)置猎唁,避免在正常瀏覽器出現(xiàn)代碼執(zhí)行兩次的情況咒劲。nomodule 表示當(dāng)前瀏覽器不支持 modules 的情況下加載使用。
<script nomodule src="https://unpkg.com/promise-polyfill@8.2.0/dist/polyfill.min.js"></script>
<script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/babel-browser-build.js"></script>
<script nomodule src="https://unpkg.com/browser-es-module-loader@0.4.1/dist/browser-es-module-loader.js"></script>
<script type="module">
import { foo } from './module.js'
console.log(foo)
</script>
Node 中應(yīng)用篇
背景
Node 中對(duì) ES modules 語(yǔ)法特性的支持還在實(shí)驗(yàn)階段诫隅。node 版本大于 8.5腐魂,腳本執(zhí)行命令添加 --experimental-modules 即可運(yùn)行 ES modules 代碼。
Node 對(duì) ES modules 特性支持的源碼
與 CommonJS 交互
1.ES modules 中可以導(dǎo)入 CommonJS 模塊逐纬。
2.CommonJS 中不能導(dǎo)入 ES modules 模塊蛔屹。
3.CommonJS 始終只會(huì)導(dǎo)出一個(gè)默認(rèn)成員。
4.import 不是解構(gòu)對(duì)象