前言:在现代前端开发中,模块化开发是不可或缺的核心能力,ES6 引入的 import 和 export 语法,彻底解决了传统 JS 全局变量污染、依赖管理混乱的问题,为工程化开发奠定了基础。本文将详细讲解导入导出的所有常用用法,搭配可直接复制运行的 Demo,覆盖基础用法、进阶技巧和常见场景,新手也能快速上手。
提示:ES6 模块需在 <script type="module"> 标签中使用,或在 Vue、React、Vite 等工程化项目中直接使用(无需额外配置);浏览器原生使用时,导入路径需包含 .js扩展名,构建工具中可省略。
一、核心概念:导出(export)------向外暴露模块接口
导出的核心作用是将当前模块(一个 JS 文件即为一个模块)中的变量、函数、类等内容暴露出去,供其他模块导入使用。ES6 导出分为具名导出 和 默认导出 两种方式,可单独使用,也可混合使用。
1. 具名导出(Named Export)
具名导出是最常用的方式,支持同时导出多个成员,导出时需指定明确的名称,导入时必须使用对应的名称(可重命名)。
特点:可多次使用 export 语句,导入时需用大括号 {} 包裹,名称必须与导出时一致(除非使用 as 重命名)。
Demo 1:具名导出的两种写法
新建 utils.js(导出方):
javascript
// 写法1:直接在声明时导出(推荐,简洁直观)
export const PI = 3.14159;
export function add() {}
export class Calculator { multiply() {} }
// 写法2:先声明,再集中导出(适合批量导出,清晰可控)
const subtract = () => {};
const divide = () => {};
export { subtract, divide }; // 用大括号包裹多个具名成员
// 进阶:具名导出重命名(解决名称冲突问题)
export { divide as safeDivide }; // 将 divide 重命名为 safeDivide 导出
2. 默认导出(Default Export)
默认导出用于导出模块的"主成员",一个模块 只能有一个默认导出,导入时可自定义名称,无需使用大括号。
特点:语法简洁,适合导出单个核心功能(如一个组件、一个主函数),导入时名称可自由定义,无需与导出时一致。
Demo 2:默认导出的三种写法
新建main.js(导出方):
javascript
// 写法1:导出匿名函数(最简洁,适合导出单个函数)
export default function(a, b) { return a + b; }
// 写法2:导出已声明的变量/函数(推荐,可读性更强)
const sayHello = (name) => `Hello, ${name}!`;
export default sayHello;
// 写法3:导出类(适合组件、工具类场景)
class User {
constructor(name, age) {
this.name = name; this.age = age;
}
showInfo() {
console.log(`姓名:${this.name},年龄:${this.age}`);
}
}
export default User;
3. 混合导出(具名 + 默认)
一个模块可同时存在一个默认导出和多个具名导出,是实际开发中最常用的场景(如导出一个主组件 + 多个辅助工具)。
Demo 3:混合导出示例
新建 mixExport.js(导出方):
二、核心用法:导入(import)------引入其他模块的接口
导入的核心作用是获取其他模块导出的成员,根据导出方式的不同,导入语法也有所区别。下面对应导出方式,讲解所有导入用法,搭配完整 Demo。
1. 导入具名导出的成员
对应具名导出,导入时需用大括号 {} 包裹成员名称,名称必须与导出时一致,可单独导入、批量导入,也可重命名导入。
Demo 4:具名导入的几种用法
新建 importNamed.js(导入方),导入上面 utils.js 中的具名成员:
javascript
// 1. 批量导入:导入指定的多个具名成员(推荐)
import { PI, add, Calculator } from './utils.js';
// 使用导入的成员
console.log(PI); // 3.14159
console.log(add(2, 3)); // 5
const calc = new Calculator(); console.log(calc.multiply(2, 3)); // 6
// 2. 单独导入:只导入需要的成员(按需导入,支持Tree-shaking)
import { subtract } from './utils.js';
console.log(subtract(5, 2)); // 3
// 3. 重命名导入:解决名称冲突(关键技巧)
import { divide as safeDivide, safeDivide as divide } from './utils.js'; console.log(safeDivide(6, 2)); // 3
console.log(divide(6, 2)); // 3(重命名后可自定义使用名称)
// 4. 整体导入:将所有具名成员导入为一个对象(不常用,适合批量使用多个成员)
import * as utils from './utils.js';
console.log(utils.PI); // 3.14159
console.log(utils.add(2, 3)); // 5
console.log(utils.subtract(5, 2)); // 3
2. 导入默认导出的成员
对应默认导出,导入时无需大括号,可自定义成员名称(无需与导出时一致),这是默认导出的核心优势。
Demo 5:默认导入的用法
新建 importDefault.js(导入方),导入上面 main.js 中的默认成员:
javascript
// 写法1:自定义名称导入(推荐,根据业务场景命名)
import myAdd from './main.js'; // 导出的是add函数,导入时命名为myAdd console.log(myAdd(2, 3)); // 5
// 写法2:使用任意名称(灵活,适合简单场景)
import hello from './main.js'; // 导出的是sayHello函数,导入时命名为hello console.log(hello('ES6')); // Hello, ES6!
// 写法3:导入默认导出的类
import UserInfo from './main.js'; // 导出的是User类,导入时命名为UserInfo
const user = new UserInfo('张三', 20); user.showInfo(); // 姓名:张三,年龄:20
3. 混合导入(默认 + 具名)
对应混合导出,导入时需先写默认导出的名称,再用大括号包裹具名成员,是实际开发中最常用的导入方式。
Demo 6:混合导入示例
新建 importMix.js(导入方),导入上面 mixExport.js 中的成员:
javascript
// 混合导入语法:默认成员在前,具名成员在后(顺序固定)
import mainFn, { msg, helperFn1, helperFn2 } from './mixExport.js'; // 使用导入的成员 mainFn(); // 这是默认导出的主函数
console.log(msg); // Hello ES6 Module helperFn1(); helperFn2();
// 进阶:混合导入 + 重命名
import myMainFn, { msg as tip, helperFn1 as fn1 } from './mixExport.js'; myMainFn(); // 这是默认导出的主函数 console.log(tip); // Hello ES6 Module fn1();
4. 特殊导入:仅执行模块(无绑定)
有些模块无需导入任何成员,仅需执行其内部代码(如初始化配置、埋点脚本、全局样式等),此时可使用无绑定导入。
Demo 7:无绑定导入示例
javascript
// 仅执行模块内部代码,不导入任何成员 import './init.js'; // init.js 中可能是初始化全局配置、埋点等代码
三、进阶技巧与注意事项
1. 动态导入(Dynamic Import)
ES6 支持动态导入,通过 import() 函数实现,返回一个 Promise,适合按需加载、条件加载(如路由懒加载、组件懒加载),解决首屏加载体积过大的问题。
javascript
// 动态导入示例(按需加载utils模块)
button.addEventListener('click', async () => {
// 动态导入,返回Promise,需用async/await或.then()处理
const utils = await import('./utils.js');
console.log(utils.add(2, 3)); // 5
console.log(utils.PI); // 3.14159 }); // 条件加载示例
if (isNeedCalculator) {
import('./utils.js').then(({ Calculator }) => {
const calc = new Calculator();
console.log(calc.multiply(2, 3)); // 6 });
})
}
})
2. 实时绑定特性
具名导出是"实时绑定"(引用),而非值拷贝,若导出模块中的成员发生变化,导入方获取到的值也会同步更新;默认导出是值拷贝(除非导出的是引用类型,如对象、数组)。
javascript
// 导出方:counter.js
export let count = 0;
export function increment() { count++; }
// 导入方:useCounter.js
import { count, increment } from './counter.js';
console.log(count); // 0
increment(); // 调用导出方的函数,修改
count console.log(count); // 1(同步更新,实时绑定)
3. 常见注意事项(避坑重点)
-
一个模块 只能有一个默认导出,但可以有多个具名导出,重复默认导出会报错。
-
具名导入/导出的名称必须一致(大小写敏感),否则会导入失败(undefined),可通过
as重命名解决。 -
import和export必须在模块顶层作用域,不能在函数、if 条件语句中使用(静态解析特性),如需动态加载,使用动态导入import()。 -
浏览器原生使用时,导入路径必须包含
.js扩展名(如./utils.js),不能省略;构建工具(Vite、Webpack)中可省略。 -
导入的成员是只读的,不能修改(如
PI = 3.14会报错),避免破坏模块封装性。
四、完整可运行示例(整合所有用法)
下面提供一套完整的 Demo,包含导出方和导入方,复制到本地即可运行(需用浏览器打开,或在工程化项目中使用)。
1. 导出方:completeExport.js
javascript
// 1. 具名导出
export const name = 'ES6 模块';
export function sum(a, b) { return a + b; }
export const tools = {
log: (msg) => console.log(`[日志]:${msg}`),
alert: (msg) => console.warn(`[警告]:${msg}`)
};
// 2. 具名导出重命名
const deleteData = (id) => console.log(`删除数据:${id}`);
export { deleteData as removeData };
// 3. 默认导出(主功能)
export default function main() { console.log('=== 完整模块演示 ==='); }
2. 导入方:completeImport.js
javascript
// 混合导入(默认 + 具名)
import main, { name, sum, tools, removeData } from './completeExport.js';
// 执行默认导出的主函数
main();
// 使用具名导出的成员
console.log('模块名称:', name); // 模块名称:ES6 模块
console.log('2 + 3 =', sum(2, 3)); // 2 + 3 = 5
tools.log('导入导出演示成功'); // [日志]:导入导出演示成功 tools.alert('注意:导入的成员不可修改'); // [警告]:注意:导入的成员不可修改 removeData(1001); // 删除数据:1001
// 动态导入示例
setTimeout(async () => { console.log('\n=== 动态导入演示 ===');
const module = await import('./completeExport.js');
console.log(module.name); // ES6 模块
console.log(module.sum(3, 4)); // 7
}, 1000);
3. 运行方式
新建 index.html,引入导入方文件,添加 type="module" 属性:
javascript
<!DOCTYPE html> ES6 导入导出演示
用浏览器打开 index.html,打开开发者工具(F12),在 Console 面板即可看到运行结果。
五、总结
ES6 导入导出的核心是"模块化隔离"和"显式依赖",掌握以下关键点,就能应对所有开发场景:
-
导出分两种:具名导出(多个,需匹配名称)、默认导出(1个,可自定义名称),支持混合导出。
-
导入对应两种:具名导入(用
{},名称匹配)、默认导入(无{},名称自定义),混合导入需先默认后具名。 -
进阶技巧:重命名(
as)、动态导入(import())、实时绑定,避坑重点是顶层作用域、路径规范和只读特性。
模块化是现代前端的基础,熟练掌握 import 和 export,能让你的代码更具可维护性、可复用性,为后续学习工程化工具(Vite、Webpack)打下坚实基础。
如果觉得有用,欢迎点赞收藏,如有疑问或补充,评论区留言交流