六维教程

ES6 模块化

为什么需要模块化

回顾之前的写法:所有 JS 都写在一个文件里,页面靠多个 <script src> 按顺序加载。代码量一大,三个问题立刻冒出来:

  1. 全局变量互相污染:两个文件里都声明了 let count,后加载的直接覆盖前面的——你根本不知道哪个文件改坏了状态。
  2. 依赖顺序靠自觉a.js 里用了 b.js 的函数,就必须保证 <script> 里 b 在 a 之前,顺序一乱就报”未定义”,错得莫名其妙。
  3. 名字越来越长:为了回避冲突,只能把函数起成 userService.loginorderUtils.calcTotal 这种长名,绕来绕去。

ES6 的模块化就是为了解决这套乱局:每个文件是独立的模块,只有通过 export 主动导出的东西外界才看得到,其余全部与外界隔离;需要用时再 import 取进来。这样互相不碰、依赖关系一目了然。

  • 想暴露哪些内容 → 用 export 导出。
  • 想用其他文件的内容 → 用 import 导入。

这就是从”写脚本”到”写工程”的跨越。

模块化概念

  • 模块:一个 .js 文件。
  • export:这个模块”交出什么”(导出)。
  • import:别的模块”拿走什么”被引入。

默认导入导出(default)

每个模块可以有一个”默认导出”,导入时名字随意起:

// a.js —— 导出
export default function greet(name) {
  console.log('你好,' + name);
}

// b.js —— 导入(名字自己起)
import greet from './a.js';
greet('小明');

特点:

  • 一个模块只能有一个 export default
  • 导入时不需要知道源文件导出的具体名字。

命名导入导出(named)

基本用法

每个模块可以导出多个”命名的”值,导入时名字必须一致(可重命名):

// utils.js
export const PI = 3.14;
export function double(n) {
  return n * 2;
}

// main.js
import { PI, double } from './utils.js';
console.log(PI);      // 3.14
console.log(double(4)); // 8

按需导入 & 重命名

// 只导入需要的
import { double } from './utils.js';

// 改名导入(避免冲突)
import { double as times2 } from './utils.js';

整体导入

把模块所有命名导出汇总到一个对象:

// main.js
import * as utils from './utils.js';
console.log(utils.PI);      // 3.14
console.log(utils.double(5)); // 10

默认 + 命名混合

同一个模块可以同时有默认导出和命名导出:

// index.js
export default function main() {}
export const version = '1.0';
export function helper() {}
// app.js
import main, { version, helper } from './index.js';

Vue 里几乎处处都是模块化:

// 示例:导入 Vue 的 API
import { ref, computed } from 'vue';      // 命名导入
import App from './App.vue';              // 默认导入(组件)

速查手册

场景 写法
导入默认导出 import x from './mod.js'
导入命名导出 import { a, b } from './mod.js'
整体导入 import * as ns from './mod.js'
默认 + 命名混合 import def, { a } from './mod.js'
上一篇
ES6 异步编程
下一篇
TypeScript 教程