溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript中的模塊、Import和Export有什么用

發(fā)布時(shí)間:2020-12-30 09:17:26 來源:億速云 閱讀:183 作者:小新 欄目:web開發(fā)

小編給大家分享一下JavaScript中的模塊、Import和Export有什么用,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

在互聯(lián)網(wǎng)的洪荒時(shí)代,網(wǎng)站主要用 HTML和 CSS 開發(fā)的。如果將 JavaScript 加載到頁面中,通常是以小片段的形式提供效果和交互,一般會(huì)把所有的 JavaScript 代碼全都寫在一個(gè)文件中,并加載到一個(gè) script 標(biāo)簽中。盡管可以把 JavaScript 拆分為多個(gè)文件,但是所有的變量和函數(shù)仍然會(huì)被添加到全局作用域中。

但是后來 JavaScript 在瀏覽器中發(fā)揮著重要的作用,迫切需要使用第三方代碼來完成常見任務(wù),并且需要把代碼分解為模塊化的文件,避免污染全局命名空間。

ECMAScript 2015 規(guī)范在 JavaScript 語言中引入了 module,也有了 import 和 export 語句。在本文中,我們一起來學(xué)習(xí) JavaScript 模塊,以及怎樣用 importexport 來組織代碼。

模塊化編程

在 JavaScript 中出現(xiàn)模塊的概念之前,當(dāng)我們想要把自己的代碼組織為多個(gè)塊時(shí),一般會(huì)創(chuàng)建多個(gè)文件,并且將它們鏈接為單獨(dú)的腳本。下面先舉例說明,首先創(chuàng)建一個(gè) index.html 文件和兩個(gè)JavaScript文件“ functions.jsscript.js。

index.html 文件用來顯示兩個(gè)數(shù)字的和、差、乘積和商,并鏈接到 script 標(biāo)簽中的兩個(gè) 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>
    <h2>Answers</h2>
    <h3><strong id="x"></strong> and <strong id="y"></strong></h3>

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

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

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

    <h4>pision</h4>
    <p id="pision"></p>

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

這個(gè)頁面很簡單,就不詳細(xì)說明了。

functions.js 文件中包含將會(huì)在第二個(gè)腳本中用到的數(shù)學(xué)函數(shù)。打開文件并添加以下內(nèi)容:

functions.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 的值,以及調(diào)用前面那些函數(shù)并顯示結(jié)果:

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('pision').textContent = quotient(x, y)

保存之后在瀏覽器中打開 index.html 可以看到所有結(jié)果:

JavaScript中的模塊、Import和Export有什么用

對(duì)于只需要一些小腳本的網(wǎng)站,這不失為一種有效的組織代碼的方法。但是這種方法存在一些問題:

  • 污染全局命名空間:你在腳本中創(chuàng)建的所有變量(sum、 difference 等)現(xiàn)在都存在于 window 對(duì)象中。如果你打算在另一個(gè)文件中使用另一個(gè)名為 sum 的變量,會(huì)很難知道在腳本的其它位置到底用的是哪一個(gè)值變量,因?yàn)樗鼈冇玫亩际窍嗤?window.sum 變量。唯一可以使變量私有的方法是將其放在函數(shù)的作用域中。甚至在 DOM 中名為 xid 可能會(huì)和 var x 存在沖突。

  • 依賴管理:必須從上到下依次加載腳本來確??梢允褂谜_的變量。將腳本分別保存存為不同文件會(huì)產(chǎn)生分離的錯(cuò)覺,但本質(zhì)上與放在頁面中的單個(gè) <script> 中相同。

在 ES6 把原生模塊添加到 JavaScript 語言之前,社區(qū)曾經(jīng)嘗試著提供了幾種解決方案。第一個(gè)解決方案是用原生 JavaScript 編寫的,例如將所有代碼都寫在 objects 或立即調(diào)用的函數(shù)表達(dá)式(IIFE)中,并將它們放在全局命名空間中的單個(gè)對(duì)象上。這是對(duì)多腳本方法的一種改進(jìn),但是仍然存在將至少一個(gè)對(duì)象放入全局命名空間的問題,并沒有使在第三方之間一致地共享代碼的問題變得更加容易。

之后又出現(xiàn)了一些模塊解決方案:CommonJS 是一種在 Node.js 實(shí)現(xiàn)的同步方法,異步模塊定義(AMD)是一種異步方法,還有支持前面兩種樣式的通用方法——通用模塊定義(UMD)。

這些解決方案的出現(xiàn)使我們可以更輕松地以的形式共享和重用代碼,也就是可以分發(fā)和共享的模塊,例如 npm。但是由于存在許多解決方案,并且都不是 JavaScript 原生的,所以需要依靠 Babel、Webpack 或 Browserify之類的工具才能在瀏覽器中使用。

由于多文件方法存在許多問題,并且解決方案很復(fù)雜,所以開發(fā)人員對(duì)把模塊化開發(fā)的方法引入 JavaScript 語言非常感興趣。于是 ECMAScript 2015 開始支持 JavaScript module。

module 是一組代碼,用來提供其他模塊所使用的功能,并能使用其他模塊的功能。 export 模塊提供代碼,import 模塊使用其他代碼。模塊之所以有用,是因?yàn)樗鼈冊(cè)试S我們重用代碼,它們提供了許多可用的穩(wěn)定、一致的接口,并且不會(huì)污染全局命名空間。

模塊(有時(shí)稱為 ES 模塊)現(xiàn)在可以在原生 JavaScript 中使用,在本文中,我們一起來探索怎樣在代碼中使用及實(shí)現(xiàn)。

原生 JavaScript 模塊

JavaScript 中的模塊使用importexport 關(guān)鍵字:

  • import:用于讀取從另一個(gè)模塊導(dǎo)出的代碼。

  • export:用于向其他模塊提供代碼。

接下來把前面的的 functions.js 文件更新為模塊并導(dǎo)出函數(shù)。在每個(gè)函數(shù)的前面添加 export 。

functions.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 中用 import 從前面的 functions.js 模塊中檢索代碼。

注意import 必須始終位于文件的頂部,然后再寫其他代碼,并且還必須包括相對(duì)路徑(在這個(gè)例子里為 ./)。

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('pision').textContent = quotient(x, y)

注意:要通過在花括號(hào)中命名單個(gè)函數(shù)來導(dǎo)入。

為了確保代碼作為模塊導(dǎo)入,而不是作為常規(guī)腳本加載,要在 index.html 中的 script 標(biāo)簽中添加type="module"。任何使用 importexport 的代碼都必須使用這個(gè)屬性:

index.html

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

由于受限于 CORS 策略,必須在服務(wù)器環(huán)境中使用模塊,否則會(huì)出現(xiàn)下面的錯(cuò)誤:

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.

模塊與常規(guī)腳本不一樣的地方:

  • 模塊不會(huì)向全局(window)作用域添加任何內(nèi)容。

  • 模塊始終處于嚴(yán)格模式。

  • 在同一文件中把同一模塊加載兩次不會(huì)出問題,因?yàn)槟K僅執(zhí)行一次

  • 模塊需要服務(wù)器環(huán)境。

模塊仍然經(jīng)常與打包程序(如 Webpack)一起配合使用,用來增加對(duì)瀏覽器的支持和附加功能,但它們也可以直接用在瀏覽器中。

接下來探索更多使用 importexport 語法的方式。

命名導(dǎo)出

如前所述,使用 export 語法允許你分別導(dǎo)入按名稱導(dǎo)出的值。以這個(gè) function.js 的簡化版本為例:

functions.js

export function sum() {}
export function difference() {}

這樣允許你用花括號(hào)按名稱導(dǎo)入 sumdifference

script.js

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

也可以用別名來重命名該函數(shù)。這樣可以避免在同一模塊中產(chǎn)生命名沖突。在這個(gè)例子中,sum 將重命名為 add,而 difference 將重命名為 subtract

script.js

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

add(1, 2) // 3

在這里調(diào)用 add() 將產(chǎn)生 sum() 函數(shù)的結(jié)果。

使用 * 語法可以將整個(gè)模塊的內(nèi)容導(dǎo)入到一個(gè)對(duì)象中。在這種情況下,sumdifference 將成為 mathFunctions 對(duì)象上的方法。

script.js

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

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

原始值、函數(shù)表達(dá)式和定義、異步函數(shù)、類和實(shí)例化的類都可以導(dǎo)出,只要它們有標(biāo)識(shí)符就行:

// 原始值
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']

// 函數(shù)表達(dá)式
export const sum = (x, y) => x + y

// 函數(shù)定義
export function difference(x, y) {
  return x - y
}

// 匿名函數(shù)
export async function getBooks() {}

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

// 實(shí)例化類
export const book = new Book('Lord of the Rings', 'J. R. R. Tolkein')

所有這些導(dǎo)出都可以成功被導(dǎo)入。接下來要探討的另一種導(dǎo)出類型稱為默認(rèn)導(dǎo)出。

默認(rèn)導(dǎo)出

在前面的例子中我們導(dǎo)出了多個(gè)命名的導(dǎo)出,并分別或作為一個(gè)對(duì)象導(dǎo)入了每個(gè)導(dǎo)出,將每個(gè)導(dǎo)出作為對(duì)象上的方法。模塊也可以用關(guān)鍵字 default 包含默認(rèn)導(dǎo)出。默認(rèn)導(dǎo)出不使用大括號(hào)導(dǎo)入,而是直接導(dǎo)入到命名標(biāo)識(shí)符中。

functions.js 文件為例:

functions.js

export default function sum(x, y) {
  return x + y
}

script.js 文件中,可以用以下命令將默認(rèn)函數(shù)導(dǎo)入為 sum

script.js

import sum from './functions.js'

sum(1, 2) // 3

不過這樣做很危險(xiǎn),因?yàn)樵趯?dǎo)入過程中對(duì)默認(rèn)導(dǎo)出的命名沒有做任何限制。在這個(gè)例子中,默認(rèn)函數(shù)被導(dǎo)入為 difference,盡管它實(shí)際上是 sum 函數(shù):

script.js

import difference from './functions.js'

difference(1, 2) // 3

所以一般首選使用命名導(dǎo)出。與命名導(dǎo)出不同,默認(rèn)導(dǎo)出不需要標(biāo)識(shí)符——原始值本身或匿名函數(shù)都可以用作默認(rèn)導(dǎo)出。以下是用作默認(rèn)導(dǎo)出的對(duì)象的示例:

functions.js

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

可以用以下命令將其作為 book 導(dǎo)入:

functions.js

import book from './functions.js'

同樣,下面的例子演示了如何將匿名箭頭函數(shù)導(dǎo)出為默認(rèn)導(dǎo)出:

functions.js

export default () => 'This function is anonymous'

可以這樣導(dǎo)入:

script.js

import anonymousFunction from './functions.js'

命名導(dǎo)出和默認(rèn)導(dǎo)出可以彼此并用,例如在這個(gè)模塊中,導(dǎo)出兩個(gè)命名值和一個(gè)默認(rèn)值:

functions.js

export const length = 10
export const width = 5

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

可以用以下命令導(dǎo)入這些變量和默認(rèn)函數(shù):

script.js

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

calculatePerimeter(length, width) // 30

現(xiàn)在默認(rèn)值和命名值都可用于腳本了。

看完了這篇文章,相信你對(duì)“JavaScript中的模塊、Import和Export有什么用”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI