Skip to content

JavaScript 模块化

基本知识

为了让 JavaScript 更模块化、更整洁以及更易于维护,ES6 引入了在多个 JavaScript 文件之间共享代码的机制。 它可以导出文件的一部分供其它文件使用,然后在需要它的地方按需导入

HTML中导入模块,需要定义属性 type="module",模块总是会在所有HTML解析后才执行

html
<script type="module" src="filename.js"></script>
<!-- 使用了 module 类型的脚本可以使用 import 和 export 特性 -->
  • 模块都有独立的顶级作用域,与普通script标签不同,不同模块不能互相访问
html
<script type="module">
  let test = "Hello World"
</script>

<script type="module">
  alert(test) // Error
</script>
  • 模块在导入时只执行一次解析,之后的导入不会再执行模块代码,而使用第一次解析结果,并共享数据
html
<script type="module" src="test.js"></script>
<script type="module" src="test.js"></script>

导入导出

ES6 使用基于文件的模块,即一个文件一个模块

  • 使用export 将开发的接口导出
  • 使用import 导入模块接口
  • 使用*可以导入全部模块接口
  • 导出是以引用方式导出,无论是标量还是对象,即模块内部变量发生变化将影响已经导入的变量

下面是对math.js模块进行导出

js
// 整体导出
const add = (x, y) => x + y
const subtract = (x, y) => x - y
export { add, subtract }

// 单个导出
export const add = (x, y) => x + y
export const subtract = (x, y) => x - y

导入分为两种:具名导入、批量导入

  • 具名导入(建议使用)
js
import { add, subtract } from './math.js'
// 用这种方式导入时,相对路径(./)和文件扩展名(.js)都是必需的
  • 批量导入(*
js
// import 语句会创建一个 addModule 的对象(命名自定义)
import * as addModule from "./math.js"

// addModule 对象包含 math.js 文件里的所有导出,可以直接访问其中的函数
myMathModule.add(2,3)
myMathModule.subtract(5,3)

别名

可以为导入和导出的模块起别名,使用as关键字

  • 有些导出的模块命名过长,起别名更简洁
  • 本模块与导入模块重名时,可以通过起别名防止冲突
js
// 导入
import { add as addFunc, subtract as subtractFunc } from './math.js'

// 导出
export { add as addFunc, subtract as subtractFunc }

默认导出

在文件中只有一个类或需要导出的时候,通常会使用默认导出语法,它也常常用于给文件或者模块创建返回值

使用default 定义默认导出的接口,导入时不需要使用 {}

  • 默认导出可以不命名,也可以为默认导出自定义别名
  • 只能有一个默认导出
  • 如果将导出命名为default也算默认导出
js
// 导出
export default function add(x, y) {
  return x + y
}

// 导入
import add from "./math.js"
// add只是变量名,对应 math.js 文件的任何默认导出值。在导入默认导出时,可以任意命名

如有多个函数或变量

js
const baseURL = 'https://www.baidu.com/'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)
export default {
  baseURL,
  getArraySum
}

混合导出

模块可以同时存在默认导出与命名导出

  • 使用export default 导出默认接口
  • 使用 export {} 导出普通接口
js
// 导出(math.js)
const baseURL = 'https://www.baidu.com/'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)
function add(x, y) {
  return x + y
}
export { baseURL, getArraySum, add as default } // 将导出命名为default也算默认导出

// 导入
import { baseURL, getArraySum } from './math.js' // 对应export
import addFunc from './math.js' // 对应export default
  • 可以使用一条语句导入默认接口与常规接口
js
import { baseURL, getArraySum }, addFunc from './math.js'
  • 也可以使用别名导入默认导出
js
import { baseURL, getArraySum, default as addFunc } from './math.js'
  • 如果是批量导入,可以使用 default 获得默认导出
js
import * as api from './math.js'
api.default.add()

导出合并

可以将导入的模块重新导出使用,将所有模块合并到一个入口文件中

  • math.js
js
export const add = (x, y) => x + y
export const subtract = (x, y) => x - y
  • base.js
js
const baseURL = 'https://www.baidu.com/'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)
export default {
  baseURL,
  getArraySum
}

统一导出

js
export * as math from "./math.js";
// 默认模块需要单独导出
export { default as base } from "./base.js";

动态加载

使用 import 必须在顶层静态导入模块,而使用import() 函数可以动态导入模块,它返回一个 promise 对象

不在顶层静态导入时是错误的,但使用动态加载却可以

js
if (true) {
  import { add, subtract } from "./math.js"; // Error
  const res = import(./math.js)
}

Web APIs

最近更新