Skip to content

ES6 模块化规范

ES6模块化规范是一个官方标准的规范, 在语言标准的层面上实现了模块化功能

是目前最流行的模块化规范, 且浏览器与服务端均支持该规范

初步上手

  • 导出: school.js
js
export const name = '家里蹲大学'
export const slogan = '吃饭, 睡觉, 打豆豆'

export function getTel() {
  return '010-987650321'
}
  • 导出: student.js
js
export const name = '张三'
export const motto = '法外狂徒'

export function getHobby() {
  return ['抽烟', '喝酒', '烫头']
}
  • 导入: index.js
js
/*
  *: 全部
  as: 作为
  school / student 名称
  导入 school.js / school.js 中全部模块, 名称叫做 school / student
*/
import * as school from './school.js'
import * as student from './school.js'

console.log(school)
console.log(student)
  • 引用: index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>
<body>
  <script type="module" scr="./index.js"></script>
</body>
</html>

注意

此时script标签中的type属性必须设置为module, 表示以模块的形式导入

在 Node 中运行 ES6 模块

Node环境在12.x及以上版本

  • 方式一: 将.js文件改完.msj
  • 方式二: 在同目录新建package.json文件, 添加"type": "module"
json
{
  "type": "module"
}

导出数据

ES6模块化提供了3中导出方式:

  1. 分别导出
  2. 统一导出
  3. 默认导出
  • 分别导出
js
export const name = '张三'
export function getTel() {
  return '16612356789'
}
  • 统一导出
js
const name = '张三'
function getTel() {
  return '16612356789'
}

export { name, getTel }

注意

此时export后面的{}不是对象, 只是类似于对象的结构, 若写成: export { name: name }则会报错

  • 默认导出
js
const name = '张三'
function getTel() {
  return '16612356789'
}

export default { name, getTel }

注意

此时export default后面的{}是对象格式

  • 备注: 上述3中导出方式可以同时使用
js
// 分别导出
export const name = '张三'
const age = 18
function getTel() {
  return '16612356789'
}

// 统一导出
export { age }
// 默认导出
export default { getTel }

导入数据

对于ES6模块化来说, 使用哪种导入方式, 取决于导出的方式

  • 导入全部(通用)
js
import * as school from './school.js'
  • 命名导入, 对应导出方式: 分别导出, 统一导出
js
import { name, getTel as mobile } from './school.js'
  • 默认导入, 对应导出方式: 默认导出
js
import school from './school.js'
  • 命名导入默认导入可以混合使用
js
import name, { getTel } from './school.js'
  • 动态导入(通用)
js
btn.onclick = async() => {
  const res = await import('./school.js')
  console.log(res)
}
  • import可以不接收任何数据
js
import './school.js'

数据引用问题

示例一

以下代码没有使用模块化, 输出结果是什么?

  • count.js
js
function count() {
  let sum = 1
  function increment() {
    sum += 1
  }
  return { sum, increment }
}

const { sum, increment } = count()

console.log(sum)
increment()
increment()
console.log(sum)

结论

第一个console.log(sum)输出: 1

第二个console.log(sum)输出: 1

原因: const { sum, increment } = count()中的sum只是结构赋值的新变量名, 与count()函数中的sum没有关系

示例二

以下代码使用CommonJS规范, 输出结果是什么?

  • count.js
js
let sum = 1
function increment() {
  sum += 1
}

module.exports = { sum, increment }
  • index.js
js
const { sum, increment } = require('./count.js')

console.log(sum)
increment()
increment()
console.log(sum)

结论

第一个console.log(sum)输出: 1

第二个console.log(sum)输出: 1

原因: 跟上例一样, const { sum, increment } = require('./count.js')中的sum只是结构赋值的新变量名, 与count.js中的sum没有关系

示例三

以下代码使用ES6模块化规范, 输出结果是什么?

  • count.js
js
let sum = 1
function increment() {
  sum += 1
}

export { sum, increment }
  • index.js
js
import { sum, increment } from './count.js'

console.log(sum)
increment()
increment()
console.log(sum)

结论

第一个console.log(sum)输出: 1

第二个console.log(sum)输出: 3

原因: import { sum, increment } from './count.js'中的sumcount.js中的sum是同一块内存空间, 这是ES6中的数据引用(符号绑定)问题

ES6模块化规范规定了不能修改import引入的基本数据类型的值

为了规避意外修改值的情况, 需要使用const sum = 1sum设置为常量, 不要使用varlet定义变量