ES6 模块化
为什么需要模块化
回顾之前的写法:所有 JS 都写在一个文件里,页面靠多个 <script src> 按顺序加载。代码量一大,三个问题立刻冒出来:
- 全局变量互相污染:两个文件里都声明了
let count,后加载的直接覆盖前面的——你根本不知道哪个文件改坏了状态。 - 依赖顺序靠自觉:
a.js里用了b.js的函数,就必须保证<script>里 b 在 a 之前,顺序一乱就报”未定义”,错得莫名其妙。 - 名字越来越长:为了回避冲突,只能把函数起成
userService.login、orderUtils.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' |