## 發展概述 >  > - > 網景領航員 (Netscape Navigator 2):第一個支援 JavaScript 以及 GIFs 的瀏覽器 ([source](https://en.wikipedia.org/wiki/Netscape_Navigator_2)) > JavaScript 早期為輕量的腳本式語言,僅用於網頁中的簡單使用者互動。 隨著網際網路發展,程式碼的規模也跟著需求逐漸成長,然而由於原生 JavaScript 並未支援模組系統,社群於 2009 年發展出兩套主流的模組系統: * `CommonJS Modules`:主要用於伺服器端(例如`Node.js`) * `Asynchronous Module Definition` (AMD):主要用於瀏覽器端,支援非同步載入模組。`RequireJS`為以 AMD 為基礎的模組系統 最終,JavaScript 在 2015 年的 ES6 中加入模組化概念、規範及語法,以解決專案的組織、管理與維護需求。除了程式碼重複使用、避免命名衝突等優點,瀏覽器端也能最佳化載入模組,相較於一次性載入整個函式庫,更加有效率。 ## 使用要點 1. 載入 ES6 模組時必須將`script`標籤的`type`屬性的值設為`module` ```html <script type="module" src="./module.js"></script> ``` 2. 無論是否使用`use strict`語法,都會自動採用嚴格模式 ([strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)) :::info 嚴格模式的特點:消除語法和程式碼的不安全處、提高性能、改進錯誤處理、禁止使用某些不推薦的特性 ::: 3. 每個檔案視為一個獨立的模組,模組中所有名稱(如變數、常數、函式、物件、類別等)的**作用域**僅限檔案內部,其他檔案無法取用。若要提供給外部使用,則需利用`export`、`import`進行匯入及匯出 4. 使用`export`關鍵字匯出,通常置於**最後方**。使用`import`關鍵字匯入,通常置於**最前方** ## 語法概要 ### 多個輸出名稱 #### `Named Export`:具名匯出 * 每個模組中可使用多個`export`直接匯出 ```javascript // module.js export let num = 1; export const sayHello = "Hello!"; export function greeting () { console.log (sayHello) }; export const user = { name: "John" }; ``` * 除了直接匯出的方法外,也可將要輸出的名稱放入`{}`中 ```javascript // module.js let num = 1; const sayHello = "Hello!"; function greeting () { console.log (sayHello) }; const user = { name: "John"}; export { num, sayHello, greeting, user }; // 將所有要輸出的名稱放入{}中 ``` * 匯出的名稱可利用`as`關鍵字重新命名 ```javascript // module.js const user = { name: "John"}; export { user as userName }; // 重新命名 ``` * 由於`export`的目標為名稱,而不是值,因此若重新賦值,匯入後取得的會是最新的值 ```javascript let num = 1; export { num }; num = 2; // 匯入此模組後取得num的值會是2 ``` #### `Import` * 匯入的名稱同樣可利用`as`關鍵字重新命名 ```javascript import { user as userName } from "./module.js"; ``` * 利用萬用字元`*`一次匯入模組中所有的輸出內容,此時輸出內容被放在一個自訂名稱的物件中,此方法屬於命名空間載入`namespace import` ```javascript // 將整個模組的內容匯入到名為module的物件中 import * as module from "./module.js"; // 以物件的方式取出值 console.log (module.sayHello); // "Hello!" ``` #### 不合法的使用 :::warning **注意:以`import`語法匯入的名稱無法重新賦值,且`import`及`export`必須放在模組頂層,無法放在區塊或函式中([靜態分析](https://en.wikipedia.org/wiki/Static_program_analysis)時不執行程式碼)** ::: * 不可重新賦值 ```javascript // module.js export let num = 1; // main.js import { num } from "./module.js"; num = 2; // 此時會報錯 ``` * 不可放在模組頂層外 ```javascript if (true) { import { num } from "./module.js"; // 不可在if中使用import } function numX() { export const x = 2; // 不可在函式中使用export } ``` ### 單一輸出名稱 #### `Default Export`:預設匯出 :::danger **注意:每個模組內只能有一個`export default`** ::: * 當準備匯出成模組的檔案中,只存在一個要輸出的目標,通常會使用`default`關鍵字 ```javascript // multiply.js function multiplyFn (num) { return num * num }; export default multiplyFn; ``` 匯入單一輸出的模組時**不需使用`{}`**,因為此時只匯入以`default`定義的輸出目標 ```javascript import multiplyFn from "./multiply.js"; multiplyFn(3); ``` 也可在匯入時更改名稱,避免命名衝突 ```javascript import square from "./multiply.js"; // 將原本的multiplyFn改為square ``` * 使用`default`關鍵字時,也可不定義名稱、直接匯出 ```javascript // module.js const sayHello = "Hello!"; // 匯出匿名函式 export default function () { console.log (sayHello) }; ``` ```javascript import greeting from "./module.js"; greeting(); // "Hello!" ``` * 要特別注意的是`default export`與`named export`不同,即使再對已進行預設匯出的名稱重新賦值,匯入後取得的並不會是最新的值 ```javascript let num = 1; export default num; num = 2; // 匯入此模組後取得num的值仍然是1 ``` #### 同時使用`export`、`export default`? `export`、`export default`可同時存在,但不建議這樣使用 ```javascript // module.js export const sayHello = "Hello!"; export default "Hi!"; ``` ```javascript import { sayHello } from "./module.js"; import sayHi from "./module.js"; // 合併匯入時,default需放在前 import sayHi, { sayHello } from "./module.js"; ``` ## 總結 ### 各式寫法 #### `named export`:顧名思義,匯出時皆需帶有名稱 ```javascript // module.js // 1 export const num = 1; // 2 const num = 1; export { num }; // 3 const num = 1; export { num as number }; ``` #### `import` ```javascript // 1 import { num } from "./module.js"; // 2 import { num as number } from "./module.js"; // 3: 將模組所有輸出項目放入module物件中 import * as module from "./module.js"; ``` #### `default export` ```javascript // module.js // 1: 可匯出純值 export default 1; // 2 const num = 1; export default num; ``` 由於一個模組中只有一個`default export`,匯入時不需要加上`{}` ```javascript // 1: 使用原始名稱 import num from "./module.js" // 2: 自訂名稱 import number from "./module.js" ``` ### 合法的語法 #### `export` ```javascript export let num = 1; // export a names variable export function sum () {}; // export a named function export default 1; // export the default export export default function sum () {}; // export the default export as a function export { greeting }; // export an existing variable export { hello as eng }; // export a variable as a new name export { hola as esp } from "module"; // export an export from another module export * from "module"; // export all exports from another module ``` #### `import` ```javascript import "module"; // import a module without any import bindings import num from "module"; // import the default export of a module import { num } from "module"; // import a named export of a module import { num as newNum } from "module"; // import a names export to a fidderent name import * as allModule from "module"; // import an entire module instance object ``` ## 參考文章 * [JavaScript modules | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) * [模組系統·從ES6開始的JavaScript學習生活](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/module_system.html) * [ES6 Module](https://chupai.github.io/posts/2104/es6module/) * [[JS] JavaScript 模組(ES Module, ESM)](https://pjchender.dev/javascript/js-es-module/) * [JavaScript :: 模組入門](https://openhome.cc/zh-tw/javascript/class-module/module/) * [模組化 (1) - Export / Import](https://medium.com/@jedy05097952/模組化-1-es6-export-import-2df769cbd81b)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.