ES 模組是 ECMAScript 的模組化標準。儘管 Node.js 已經使用 CommonJS 標準多年,但瀏覽器從未擁有模組系統,因為關鍵的決策,如模組系統,必須首先由 ECMAScript 標準化,然後由瀏覽器實現。

這個標準化過程於 ES6 完成,瀏覽器開始實現這個標準,盡力保持一切保持協調,以相同的方式工作,現在 ES 模組在 Chrome、Safari、Edge 和 Firefox(版本 60 以後)中得到支援。

模組非常強大,因為它可以將各種功能封裝起來,並將這些功能作為庫暴露給其他 JavaScript 檔案。

ES 模組支援

ES 模組語法

導入模組的語法如下:

import package from 'module-name'

而 CommonJS 使用:

const package = require('module-name')

模組是一個使用 export 關鍵字將一個或多個值(物件、函式或變數)導出的 JavaScript 檔案。例如,這個模組導出了一個將字串轉換為大寫的函式:

export default str => str.toUpperCase()

在這個例子中,模組定義了一個預設導出,所以可以是一個匿名函式。否則它需要一個名稱來區別於其他導出。

現在,任何其他的 JavaScript 模組可以透過導入它來使用 uppercase.js 提供的功能。

可以通過使用具有特殊屬性 type="module"<script> 標籤將模組添加到 HTML 頁面中:

<script type="module" src="index.js"></script>

注意:這種模組導入的行為類似於 defer 的腳本加載。請參見 使用 defer 和 async 高效加載 JavaScript

需要注意的是,使用 type="module" 加載的任何腳本都是在嚴格模式下加載的。

在這個例子中,uppercase.js 模組定義了一個預設導出,因此當我們導入它時,可以為它指定我們喜歡的名稱:

import toUpperCase from './uppercase.js'

然後我們可以使用它:

toUpperCase('test') //'TEST'

您也可以使用絕對路徑來導入模組,以引用在其他網域上定義的模組:

import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'

以下導入語法也是有效的:

import { toUpperCase } from '/uppercase.js'
import { toUpperCase } from '../uppercase.js'

但以下導入語法是無效的:

import { toUpperCase } from 'uppercase.js'
import { toUpperCase } from 'utils/uppercase.js'

它必須是絕對路徑或在名稱前加上 .//

其他導入/導出選項

我們以前看到了以下例子:

export default str => str.toUpperCase()

這創建了一個預設導出。但是在一個文件中,您可以通過使用以下語法導出多個事物:

const a = 1
const b = 2
const c = 3

export { a, b, c }

另一個模組可以使用以下方式導入所有這些導出:

import * as module from 'module'

您也可以使用解構賦值,只導入其中的一部分導出:

import { a } from 'module'
import { a, b } from 'module'

您可以使用 as 來重命名任何導入,以提高方便性:

import { a, b as two } from 'module'

您可以導入預設導出和任何非預設導出,如以下常見的 React 導入:

import React, { Component } from 'react'

這裡可以看到一個 ES 模組的例子:https://glitch.com/edit/#!/flavio-es-modules-example?path=index.html

CORS

模組使用 CORS 進行瀏覽器跨域請求。這意味著如果您引用其他網域上的腳本,它們必須具有允許跨站點加載的有效 CORS 標頭(例如 Access-Control-Allow-Origin: *)。

不支援模組的瀏覽器怎麼辦?

可以使用 type="module"nomodule 的組合:

<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

結論

ES 模組是現代瀏覽器中引入的最重要的功能之一。它們是 ES6 的一部分,但實現它們的道路非常漫長。

現在我們可以使用它們了!但我們也必須記住,在頁面上有超過幾個模組會對效能產生影響,因為這是瀏覽器在運行時必須執行的一個額外步驟。

即使 ES 模組在瀏覽器中有所支持,Webpack可能仍然是一個重要的角色,但直接在語言中內建這樣的功能對於客戶端和 Node.js 上的模組工作方式的統一來說是一個很大的優勢。