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