JavaScript >> Javascript 文檔 >  >> JavaScript

了解 JavaScript 中的模塊、導入和導出

在 Web 的早期,網站主要由 HTML 和 CSS 組成。如果將任何 JavaScript 加載到頁面中,它通常以小片段的形式提供效果和交互性。因此,JavaScript 程序通常完全編寫在一個文件中並加載到 script 標籤。開發人員可以將 JavaScript 分解為多個文件,但所有變量和函數仍將添加到全局範圍內。

但是隨著網站隨著 Angular、React 和 Vue 等框架的出現而發展,以及隨著公司創建高級 Web 應用程序而不是桌面應用程序,JavaScript 現在在瀏覽器中扮演著重要角色。因此,更需要使用第三方代碼來完成常見任務,將代碼分解為模塊化文件,並避免污染全局命名空間。

ECMAScript 2015 規範引入了模塊 到 JavaScript 語言,它允許使用 importexport 陳述。在本教程中,您將了解什麼是 JavaScript 模塊以及如何使用 importexport 來組織你的代碼。

模塊化編程

在 JavaScript 中出現模塊概念之前,當開發人員想要將他們的代碼組織成段時,他們會創建多個文件並作為單獨的腳本鏈接到它們。為了證明這一點,創建一個示例 index.html 文件和兩個 JavaScript 文件,functions.jsscript.js .

index.html 文件將顯示兩個數字的和、差、積和商,並鏈接到 script 中的兩個 JavaScript 文件 標籤。打開index.html 在文本編輯器中添加以下代碼:

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>JavaScript Modules</title>
  </head>

  <body>
    <h1>Answers</h1>
    <h2><strong id="x"></strong> and <strong id="y"></strong></h2>

    <h3>Addition</h3>
    <p id="addition"></p>

    <h3>Subtraction</h3>
    <p id="subtraction"></p>

    <h3>Multiplication</h3>
    <p id="multiplication"></p>

    <h3>Division</h3>
    <p id="division"></p>

    <script src="functions.js"></script>
    <script src="script.js"></script>
  </body>
</html>

此 HTML 將顯示變量 x 的值 和 yh2 中 標頭,以及在以下 p 中對這些變量進行操作的值 元素。 id 元素的屬性被設置為 DOM 操作,這將發生在 script.js 文件;此文件還將設置 x 的值 和 y .有關 HTML 的更多信息,請查看我們的如何使用 HTML 構建網站系列。

functions.js 文件將包含將在第二個腳本中使用的數學函數。打開functions.js 文件並添加以下內容:

函數.js
function sum(x, y) {
  return x + y
}

function difference(x, y) {
  return x - y
}

function product(x, y) {
  return x * y
}

function quotient(x, y) {
  return x / y
}

最後,script.js 文件將確定 x 的值 和 y ,對它們應用函數,並顯示結果:

script.js
const x = 10
const y = 5

document.getElementById('x').textContent = x
document.getElementById('y').textContent = y

document.getElementById('addition').textContent = sum(x, y)
document.getElementById('subtraction').textContent = difference(x, y)
document.getElementById('multiplication').textContent = product(x, y)
document.getElementById('division').textContent = quotient(x, y)

設置好這些文件並保存後,就可以打開index.html 在瀏覽器中顯示您的網站以及所有結果:

對於有少量小腳本的網站,這是一種有效的代碼劃分方式。但是,這種方法存在一些問題,包括:

  • 污染全局命名空間 :您在腳本中創建的所有變量—sum , difference 等——現在存在於 window 目的。如果您嘗試使用另一個名為 sum 的變量 在另一個文件中,很難知道在腳本中的任何位置將使用哪個值,因為它們都將使用相同的 window.sum 多變的。變量私有的唯一方法是將其放在函數範圍內。 id 之間甚至可能存在衝突 在名為 x 的 DOM 中 和 var x .
  • 依賴管理 :必須按從上到下的順序加載腳本,以確保正確的變量可用。將腳本保存為不同的文件會產生分離的錯覺,但它本質上與具有單個內聯 <script> 相同 在瀏覽器頁面中。

在 ES6 將原生模塊添加到 JavaScript 語言之前,社區試圖提出幾種解決方案。第一個解決方案是用 vanilla JavaScript 編寫的,例如在對像中編寫所有代碼或立即調用函數表達式 (IIFE),並將它們放在全局命名空間中的單個對像上。這是對多腳本方法的改進,但仍然存在將至少一個對象放在全局命名空間中的相同問題,並且沒有使第三方之間一致地共享代碼的問題變得更容易。

之後,出現了一些模塊解決方案:CommonJS,一種在 Node.js 中實現的同步方法,異步模塊定義(AMD),一種異步方法,以及通用模塊定義(UMD),旨在成為一個通用的支持以前兩種樣式的方法。

這些解決方案的出現使開發人員更容易以的形式共享和重用代碼 ,可以分發和共享的模塊,例如在 npm 上找到的模塊。然而,由於有很多解決方案,但沒有一個是 JavaScript 原生的,因此必須實現 Babel、Webpack 或 Browserify 等工具才能在瀏覽器中使用模塊。

由於多文件方法的許多問題以及所提出的解決方案的複雜性,開發人員有興趣將模塊化編程方法引入 JavaScript 語言。因此,ECMAScript 2015 支持使用 JavaScript 模塊。

一個模塊 是一組代碼,充當接口,為其他模塊提供功能,並能夠依賴其他模塊的功能。一個模塊導出 提供代碼和導入 使用其他代碼。模塊很有用,因為它們允許開發人員重用代碼,它們提供了許多開發人員可以使用的穩定、一致的接口,並且它們不會污染全局命名空間。

模塊(有時稱為 ECMAScript 模塊或 ES 模塊)現在可以在 JavaScript 中本地使用,在本教程的其餘部分中,您將探索如何在代碼中使用和實現它們。

原生 JavaScript 模塊

JavaScript 中的模塊使用 importexport 關鍵詞:

  • import :用於讀取從另一個模塊導出的代碼。
  • export :用於向其他模塊提供代碼。

要演示如何使用它,請更新您的 functions.js 文件成為一個模塊並導出功能。您將添加 export 在每個函數前面,這將使它們可用於任何其他模塊。

將以下突出顯示的代碼添加到您的文件中:

函數.js
export function sum(x, y) {
  return x + y
}

export function difference(x, y) {
  return x - y
}

export function product(x, y) {
  return x * y
}

export function quotient(x, y) {
  return x / y
}

現在,在 script.js ,您將使用 importfunctions.js 檢索代碼 文件頂部的模塊。

將以下突出顯示的代碼添加到 script.js

script.js
import { sum, difference, product, quotient } from './functions.js'

const x = 10
const y = 5

document.getElementById('x').textContent = x
document.getElementById('y').textContent = y

document.getElementById('addition').textContent = sum(x, y)
document.getElementById('subtraction').textContent = difference(x, y)
document.getElementById('multiplication').textContent = product(x, y)
document.getElementById('division').textContent = quotient(x, y)

請注意,各個函數是通過在花括號中命名來導入的。

為了確保此代碼作為模塊而不是常規腳本加載,請添加 type="module"script index.html 中的標籤 .任何使用 import 的代碼 或 export 必須使用這個屬性:

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

此時,您將能夠重新加載包含更新的頁面,並且網站現在將使用模塊。瀏覽器支持非常高,但是可以使用 caniuse 來檢查哪些瀏覽器支持它。請注意,如果您將文件作為本地文件的直接鏈接查看,則會遇到此錯誤:

Access to script at 'file:///Users/your_file_path/script.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

由於 CORS 政策,Modules 必須在服務器環境中使用,您可以在本地使用 http-server 或在 Internet 上使用託管服務提供商進行設置。

模塊在以下幾個方面不同於常規腳本:

  • 模塊不會向全局(window ) 範圍。
  • 模塊始終處於嚴格模式。
  • 在同一個文件中加載同一個模塊兩次沒有效果,因為模塊只執行一次/
  • 模塊需要服務器環境。

模塊仍然經常與 Webpack 等捆綁器一起使用,以增加對瀏覽器的支持和附加功能,但它們也可以直接在瀏覽器中使用。

接下來,您將探索 importexport 可以使用語法。

命名導出

如前所述,使用 export 語法將允許您單獨導入已按名稱導出的值。以 functions.js 的簡化版本為例 :

函數.js
export function sum() {}
export function difference() {}

這會讓你導入 sumdifference 使用花括號按名稱:

script.js
import {sum, difference} from './functions.js'

也可以使用別名來重命名函數。您可以這樣做以避免同一模塊內的命名衝突。在本例中,sum 將重命名為 adddifference 將重命名為 subtract .

script.js
import {
  sum as add,
  difference as subtract
} from './functions.js'

add(1, 2) // 3

調用 add() 這裡將產生 sum() 的結果 功能。

使用 * 語法,您可以將整個模塊的內容導入到一個對像中。在這種情況下,sumdifference 將成為 mathFunctions 上的方法 對象。

script.js
import * as mathFunctions from './functions.js'

mathFunctions.sum(1, 2) // 3
mathFunctions.difference(10, 3) // 7

原始值、函數表達式和定義、異步函數、類和實例化類都可以導出,只要它們有標識符即可:

// Primitive values
export const number = 100
export const string = 'string'
export const undef = undefined
export const empty = null
export const obj = {name: 'Homer'}
export const array = ['Bart', 'Lisa', 'Maggie']

// Function expression
export const sum = (x, y) => x + y

// Function defintion
export function difference(x, y) {
  return x - y
}

// Asynchronous function
export async function getBooks() {}

// Class
export class Book {
  constructor(name, author) {
    this.name = name
    this.author = author
  }
}

// Instantiated class
export const book = new Book('Lord of the Rings', 'J. R. R. Tolkein')

所有這些導出都可以成功導入。您將在下一節中探討的另一種導出類型稱為默認導出。

默認導出

在前面的示例中,您導出了多個命名導出並將它們單獨導入或作為一個對象導入,每個導出作為對像上的一個方法。模塊還可以包含默認導出,使用 default 關鍵詞。默認導出不會使用大括號導入,而是直接導入到命名標識符中。

functions.js 的以下內容為例 文件:

函數.js
export default function sum(x, y) {
  return x + y
}

script.js 文件,您可以將默認函數導入為 sum 帶有以下內容:

script.js
import sum from './functions.js'

sum(1, 2) // 3

這可能很危險,因為在導入期間您可以命名默認導出沒有任何限制。在本例中,默認函數導入為 difference 雖然它實際上是 sum 功能:

script.js
import difference from './functions.js'

difference(1, 2) // 3

因此,通常首選使用命名導出。與命名導出不同,默認導出不需要標識符——原始值本身或匿名函數都可以用作默認導出。以下是用作默認導出的對象示例:

函數.js
export default {
  name: 'Lord of the Rings',
  author: 'J. R. R. Tolkein',
}

您可以將其導入為 book 帶有以下內容:

函數.js
import book from './functions.js'

同樣,以下示例演示了將匿名箭頭函數導出為默認導出:

函數.js
export default () => 'This function is anonymous'

這可以使用以下 script.js 導入 :

script.js
import anonymousFunction from './functions.js'

命名導出和默認導出可以一起使用,例如在這個模塊中導出兩個命名值和一個默認值:

函數.js
export const length = 10
export const width = 5

export default function perimeter(x, y) {
  return 2 * (x + y)
}

您可以使用以下命令導入這些變量和默認函數:

script.js
import calculatePerimeter, {length, width} from './functions.js'

calculatePerimeter(length, width) // 30

現在腳本可以使用默認值和命名值。

結論

模塊化編程設計實踐允許您將代碼分成單獨的組件,這有助於使您的代碼可重用和一致,同時還可以保護全局命名空間。可以使用 import 在原生 JavaScript 中實現模塊接口 和 export 關鍵詞。在本文中,您了解了 JavaSvript 中模塊的歷史,如何將 JavaScript 文件分離為多個頂級腳本,如何使用模塊化方法更新這些文件,以及 importexport 命名和默認導出的語法。

要了解有關 JavaScript 中模塊的更多信息,請閱讀 Mozilla 開發人員網絡上的模塊。如果您想探索 Node.js 中的模塊,請嘗試我們的如何創建 Node.js 模塊教程。


Tutorial JavaScript 教程
  1. 取消獲取請求,以及抽象它的方法

  2. JavaScript 中帶有函數的高級功能

  3. 使用子字符串生成 4 位隨機數

  4. 將 Expo 應用程序分離到 ExpoKit

  5. Web 組件的測試工作流程

  6. 十大在線 JavaScript 工具

  7. 如何將對像從 JavaScript 發送到 Struts 2 中的 Action 類?

  1. Node.js 樣板/從頭開始的身份驗證 - (express, graphql, mongodb)

  2. React、Vue 和 Svelte:比較多複選框綁定

  3. 動態加載 css 樣式表在 IE 上不起作用

  4. 2022 年使用哪些 Web 開發堆棧 - 企業主指南

  5. 模塊聯合和 Angular Service Worker (PWA)

  6. 使用 Deno 編寫一個小 API

  7. 重構 JavaScript 開發人員的 TypeScript 第 2 部分(共 2 部分)

  1. 使用 Google Cloud Run 在 GCP 上部署 React 應用

  2. 通過消除渲染阻塞 CSS 和 JavaScript 來提高網站性能

  3. 使用全棧來增加你的收入

  4. 以高性能方式嵌入 Youtube 視頻