1. 程式人生 > >JavaScript ES 模組:現代化前端程式設計必備技能

JavaScript ES 模組:現代化前端程式設計必備技能

自從 ES 模組被新增到規範中後,JavaScript 中的模組就更加簡單了。模組按檔案分開,非同步載入。匯出是用 `export` 關鍵字定義的;值可以用 `import` 關鍵字匯入。 雖然匯入和匯出單個值的基礎知識非常容易掌握和使用,但還有許多其他方法可以使用 ES 模組來使你的匯入和匯出按照你需要的方式工作。在本文中,我將介紹你可以在模組中匯出和匯入的所有方法。 需要記住的一點是,匯出和靜態匯入只能發生在模組的最外層。你不能從函式、if 語句或任何其他塊中匯出或靜態匯入。另外,動態匯入可以在函式中完成,我們將在本文最後討論它。 ## 匯出 ### 預設匯出 每個模組都有一個 "預設 "匯出,它代表了模組匯出的主要值。可能會有更多的匯出值,但預設匯出值代表模組的定義。一個模組中只能有一個預設匯出。 ```js const fruitBasket = new FruitBasket() export default fruitBasket ``` 注意,在預設匯出之前,我必須先定義該值。如果我想,我也可以立即匯出我的值,而不把它分配給一個變數,但這樣我就不能在匯出的同時將其賦值給一個變數。 我們可以預設匯出一個函式宣告和一個類宣告,而不需要先把它分配給一個變數。 ```js export default function addToFruitBasket(fruit) { // ... } ``` 我們甚至可以將字面值作為預設匯出。 ```js export default 123 ``` ### 命名匯出 任何變數宣告都可以在建立時匯出,這將建立一個 "命名匯出",使用變數名作為匯出名。 ```js export const fruitBasket = new FruitBasket() ``` 我們還可以立即匯出函式和類的宣告。 ```js export function addToFruitBasket(fruit) { // ... } export class FruitBasket { // ... } ``` 如果我們想匯出一個已經定義好的變數,我們可以通過大括號把變數名包裝為物件來實現。 ```js const fruitBasket = new FruitBasket() export { fruitBasket } ``` 我們甚至可以使用 `as` 關鍵字來重新命名我們的匯出,使之與變數名不同。如果需要,我們還可以同時匯出其他變數。 ```js const fruitBasket = new FruitBasket() class Apple {} export { fruitBasket as basketOfFruit, Apple } ``` ### 聚合匯出 我們還會經常遇到這種情況,就是從一個模組匯入模組,然後立即匯出這些值。比如這樣: ```js import fruitBasket from './fruitBasket.js' export { fruitBasket } ``` 當你要同時匯入和匯出很多東西時,這可能會變得很繁瑣。ES 模組允許我們同時匯入和匯出多個值。 ```js export * from './fruitBasket.js' ``` 這將把 `./fruitBasket.js` 中所有命名匯出重新包裝在一起再匯出,但它不會匯出預設匯出值,因為一個模組只能有一個預設匯出值。如果我們要匯入和匯出多個具有預設匯出的模組,哪個值將成為匯出模組的預設匯出值呢? 我們可以專門從其他檔案中匯出預設模組,或者在重新匯出時為預設匯出命名。 ```js export { default } from './fruitBasket.js' // 或者 export { default as fruitBasket } from './fruitBasket.js' ``` 我們也可以有選擇地從另一個模組匯出不同的專案,而不是把所有的專案都重新匯出。在這種情況下,我們也使用大括號。 ```js export { fruitBasket as basketOfFruit, Apple } from './fruitBasket.js' ``` 最後,我們可以使用 `as` 關鍵字將整個模組打包成一個單獨的命名匯出。假設我們有以下檔案: ```js // fruits.js export class Apple {} export class Banana {} ``` 現在我們可以將其打包成一個單獨的匯出物件,這個物件包含了所有命名匯出和預設匯出物件。 ```js export * as fruits from './fruits.js' // { Apple: class Apple, Banana: class Banana } ``` ## 匯入 ### 預設匯入 當匯入一個預設值時,我們需要給它指定一個名字。既然是預設值,我們給它取什麼名字並不重要。 ```js import fruitBasketList from './fruitBasket.js' ``` 我們也可以同時匯入所有的匯出,包括命名匯出和預設匯出。這將會把所有的匯出放到一個物件中,而預設匯出將被賦予 "default "的屬性名。 ```js import * as fruitBasket from './fruitBasket.js' // { default: fruitBasket } ``` ### 命名匯入 我們可以通過用大括號包裝匯出的名稱來匯入任何命名匯出。 ```js import { fruitBasket, Apple } from './fruitBasket.js' ``` 我們也可以在匯入時使用 `as` 關鍵字重新命名匯入。 ```js import {fruitBasket as basketOfFruit, Apple} from './fruitBasket.js' ``` 我們也可以在同一個匯入語句中混合命名匯出和預設匯出。預設匯出的內容會先列出,然後是大括號內的命名匯出內容。 ```js import fruitBasket, { Apple } from './fruitBasket.js' ``` ### 副作用匯入 有時候一個模組並沒有匯出值,我們只希望把該模組匯入進來立即執行。匯入這樣的一個模組時,不需要在檔案中列出任何匯出值。這被稱為”副作用(side-effect)“匯入,它將直接執行模組中的程式碼而不提供任何匯出值。 ```js import './fruitBasket.js' ``` ### 動態匯入 有時我們在匯入檔案之前並不知道檔案的名稱。或者我們在執行程式碼到一半的時候才需要匯入一個檔案,我們可以使用動態匯入在程式碼中的任何位置匯入模組。之所以稱之為 "動態",是因為匯入的路徑可能是不確定的,可以是字串變數也可以是字串表示式,而不像靜態匯入那樣必須是一個字串字面量。 由於 ES 模組是非同步的,所以模組不會立即可用。我們必須等待它被載入後才能對它做事情。正因為如此,動態匯入會返回一個解析模組的 Promise。 ```js async function createFruit(fruitName) { try { const FruitClass = await import(`./${fruitName}.js`) } catch { console.error('Error getting fruit class module:', fruitName) } return new FruitClass() } ``` ## 總結 ES 匯出的內容可以是值(包括變數和字面量)也可以是類和函式的宣告,從匯出方式上可以分為預設匯出、命名匯出和聚合匯出。根據不同的匯出方式,匯入可以分為預設匯入、命名匯入、副作用匯入和動態匯入。命名匯出和匯入均可以使用 `as` 指定別名。​匯出和靜態匯入必須在檔案的最外層,動態匯入可以在程式碼的函式中非同步