自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解 JavaScript 中的模塊、Import和Export

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

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

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

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

模塊化編程

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

index.html 文件用來顯示兩個數(shù)字的和、差、乘積和商,并鏈接到 script 標(biāo)簽中的兩個 JavaScript 文件。打開 index.html 并添加以下代碼:

index.html

 

 

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3.   <head> 
  4.     <meta charset="utf-8" /> 
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
  6.  
  7.     <title>JavaScript Modules</title> 
  8.   </head> 
  9.  
  10.   <body> 
  11.     <h1>Answers</h1> 
  12.     <h2><strong id="x"></strong> and <strong id="y"></strong></h2> 
  13.  
  14.     <h3>Addition</h3> 
  15.     <p id="addition"></p> 
  16.  
  17.     <h3>Subtraction</h3> 
  18.     <p id="subtraction"></p> 
  19.  
  20.     <h3>Multiplication</h3> 
  21.     <p id="multiplication"></p> 
  22.  
  23.     <h3>Division</h3> 
  24.     <p id="division"></p> 
  25.  
  26.     <script src="functions.js"></script> 
  27.     <script src="script.js"></script> 
  28.   </body> 
  29. </html> 

 

 

 

這個頁面很簡單,就不詳細說明了。

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

functions.js

 

  1. function sum(x, y) { 
  2.   return x + y 
  3.  
  4. function difference(x, y) { 
  5.   return x - y 
  6.  
  7. function product(x, y) { 
  8.   return x * y 
  9.  
  10. function quotient(x, y) { 
  11.   return x / y 

最后,script.js 文件用來確定 x 和 y 的值,以及調(diào)用前面那些函數(shù)并顯示結(jié)果:

script.js

 

  1. const x = 10 
  2. const y = 5 
  3.  
  4. document.getElementById('x').textContent = x 
  5. document.getElementById('y').textContent = y 
  6.  
  7. document.getElementById('addition').textContent = sum(x, y) 
  8. document.getElementById('subtraction').textContent = difference(x, y) 
  9. document.getElementById('multiplication').textContent = product(x, y) 
  10. document.getElementById('division').textContent = quotient(x, y) 

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

 

 

 

 

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

  • 污染全局命名空間:你在腳本中創(chuàng)建的所有變量(sum、 difference 等)現(xiàn)在都存在于 window 對象中。如果你打算在另一個文件中使用另一個名為 sum 的變量,會很難知道在腳本的其它位置到底用的是哪一個值變量,因為它們用的都是相同的 window.sum 變量。唯一可以使變量私有的方法是將其放在函數(shù)的作用域中。甚至在 DOM 中名為 x 的 id 可能會和 var x 存在沖突。
  • 依賴管理:必須從上到下依次加載腳本來確??梢允褂谜_的變量。將腳本分別保存存為不同文件會產(chǎn)生分離的錯覺,但本質(zhì)上與放在頁面中的單個 <script> 中相同。

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

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

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

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

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

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

原生 JavaScript 模塊

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

  • import:用于讀取從另一個模塊導(dǎo)出的代碼。
  • export:用于向其他模塊提供代碼。

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

functions.js

 

  1. export function sum(x, y) { 
  2.   return x + y 
  3.  
  4. export function difference(x, y) { 
  5.   return x - y 
  6.  
  7. export function product(x, y) { 
  8.   return x * y 
  9.  
  10. export function quotient(x, y) { 
  11.   return x / y 

在 script.js 中用 import 從前面的 functions.js 模塊中檢索代碼。

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

把 script.js 中的代碼改成下面的樣子:

script.js

 

  1. import { sum, difference, product, quotient } from './functions.js' 
  2.  
  3. const x = 10 
  4. const y = 5 
  5.  
  6. document.getElementById('x').textContent = x 
  7. document.getElementById('y').textContent = y 
  8.  
  9. document.getElementById('addition').textContent = sum(x, y) 
  10. document.getElementById('subtraction').textContent = difference(x, y) 
  11. document.getElementById('multiplication').textContent = product(x, y) 
  12. document.getElementById('division').textContent = quotient(x, y) 

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

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

index.html

  1. <script  
  2.   type="module" src="functions.js"
  3. </script> 
  4. <script  
  5.   type="module" src="script.js"
  6. </script> 

 

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

  1. 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ī)腳本不一樣的地方:

  • 模塊不會向全局(window)作用域添加任何內(nèi)容。
  • 模塊始終處于嚴(yán)格模式。
  • 在同一文件中把同一模塊加載兩次不會出問題,因為模塊僅執(zhí)行一次
  • 模塊需要服務(wù)器環(huán)境。

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

接下來探索更多使用 import 和 export 語法的方式。

命名導(dǎo)出

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

functions.js

 

  1. export function sum() {} 
  2. export function difference() {} 

這樣允許你用花括號按名稱導(dǎo)入 sum 和 difference:

script.js

 

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

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

script.js

 

  1. import { 
  2.   sum as add
  3.   difference as subtract 
  4. from './functions.js' 
  5.  
  6. add(1, 2) // 3 

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

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

script.js

 

  1. import * as mathFunctions from './functions.js' 
  2.  
  3. mathFunctions.sum(1, 2) // 3 
  4. mathFunctions.difference(10, 3) // 7 

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

 

  1. // 原始值 
  2. export const number = 100 
  3. export const string = 'string' 
  4. export const undef = undefined 
  5. export const empty = null 
  6. export const obj = {name'Homer'
  7. export const array = ['Bart''Lisa''Maggie'
  8.  
  9. // 函數(shù)表達式 
  10. export const sum = (x, y) => x + y 
  11.  
  12. // 函數(shù)定義 
  13. export function difference(x, y) { 
  14.   return x - y 
  15.  
  16. // 匿名函數(shù) 
  17. export async function getBooks() {} 
  18.  
  19. // 類 
  20. export class Book { 
  21.   constructor(name, author) { 
  22.     this.name = name 
  23.     this.author = author 
  24.   } 
  25.  
  26. // 實例化類 
  27. export const book = new Book('Lord of the Rings''J. R. R. Tolkein'

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

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

以 functions.js 文件為例:

functions.js

 

  1. export default function sum(x, y) { 
  2.   return x + y 

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

script.js

 

  1. import difference from './functions.js' 
  2.  
  3. difference(1, 2) // 3 

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

script.js

 

  1. import difference from './functions.js' 
  2.  
  3. difference(1, 2) // 3 

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

functions.js

 

  1. export default { 
  2.   name'Lord of the Rings'
  3.   author: 'J. R. R. Tolkein'

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

functions.js

 

  1. import book from './functions.js' 

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

functions.js

 

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

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

script.js

 

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

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

functions.js

 

  1. export const length = 10 
  2. export const width = 5 
  3.  
  4. export default function perimeter(x, y) { 
  5.   return 2 * (x + y) 

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

script.js

 

  1. import calculatePerimeter, {length, width} from './functions.js' 
  2.  
  3. calculatePerimeter(length, width) // 30 

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

 

總結(jié)

模塊化編程設(shè)計允許我們把代碼分成單個組件,這有助于代碼重用,同時還可以保護全局命名空間。一個模塊接口可以在原生 JavaScript 中用關(guān)鍵字 import 和 export 來實現(xiàn)。

責(zé)任編輯:華軒 來源: 前端先鋒
相關(guān)推薦

2020-12-23 14:18:43

JavaScript模塊導(dǎo)出

2013-05-08 10:36:07

JavaScriptJS詳解JavaScrip

2021-05-08 07:51:07

Vue框架前端

2015-12-24 10:05:39

JavaScripttypeofinstanceof

2017-03-20 14:45:42

JavaScript詳解

2020-07-09 08:01:48

JavaScriptES模塊

2010-09-01 15:11:09

linkimportCSS

2010-09-08 09:33:09

CSSlink@import

2016-10-11 20:33:17

JavaScriptThisWeb

2009-09-21 16:59:29

Array擴展

2009-06-10 22:07:59

JavaScriptdocument對象window對象

2010-09-08 15:13:09

Node節(jié)點Node屬性

2016-12-27 10:19:42

JavaScriptindexOf

2009-10-26 15:07:12

checkbox樹

2020-04-15 15:48:03

Node.jsstream前端

2024-04-26 08:27:15

JavaScriptCSSHTML元素

2016-08-12 11:04:17

JavaScript物聯(lián)網(wǎng)應(yīng)用

2009-11-06 13:28:19

Javascript框

2011-06-09 15:27:01

JavaScript

2010-10-09 09:56:51

JavaScriptObject對象
點贊
收藏

51CTO技術(shù)棧公眾號