模块化(module)
核心思想(ES6 Module)
ES6 模块设计追求静态化:编译时就能解析模块依赖、导入导出变量。
对比:CommonJS、AMD 只能在运行时确定依赖关系。
一个模块就是独立文件,文件内变量、函数默认私有,外部无法直接访问;想要对外暴露,必须通过 export 导出,其他文件通过 import 导入。
两大核心指令:
1. export:定义模块对外暴露的接口
2. import:引入其它模块暴露的接口
export 命令
作用:向外提供模块接口,建立接口名与内部变量一一绑定关系。
1. 导出变量
方式1:声明时直接导出
export let firstName = 'Michael';
export let lastName = 'Jackson';
export let year = 1958;
方式2:先定义,末尾统一导出(推荐写法)
便于集中查看当前模块对外暴露哪些成员
let firstName = 'Michael';
let lastName = 'Jackson';
let year = 1958;
export { firstName, lastName, year };
2. 导出函数 / Class
// 写法1
export function multiply(x, y) {
return x * y;
}
// 写法2:先定义,统一导出
function add(a, b) {
return a + b;
}
export { add };
3. 使用 as 重命名导出
对外暴露的名称可以和内部名称不一致
function multiply(x, y) {
return x * y;
}
// 内部名称multiply,外部导入名称为 multiply2
export { multiply as multiply2 };
4. 重要语法约束
export 导出的是接口绑定关系,不能直接导出字面量值!
// 报错:直接导出数值,不存在接口绑定
export 1;
// 报错:仅仅导出变量的值,不是接口
var m = 1;
export m;
// 正确写法一
export var m = 1;
// 正确写法二
var m = 1;
export { m };
// 正确写法三(重命名导出)
var n = 1;
export { n as m };
函数导出同样遵循该规则:
function f() {}
// 错误
export f;
// 正确
export function f() {}
// 正确
function f() {}
export { f };
5. 实时绑定特性(ES Module关键特性)
ES6 模块导出是动态绑定:外部拿到的是变量引用,模块内部变量更新,外部读取到的值同步更新。
区别 CommonJS:CommonJS 导出的是值拷贝,内部修改不会影响外部。
示例:
// module.js
export let count = 0;
export function inc() {
count++;
}
// app.js
import { count, inc } from './module.js';
console.log(count); // 0
inc();
console.log(count); // 1 自动更新
6. export 注意事项
export必须写在模块顶层作用域,不能放在函数、if、for 等代码块内部(静态编译要求)
// 非法
if(true){
export let a = 1;
}
- 同一名称可以重命名导出,但普通命名导出不允许重名接口;
- 命名导出和默认导出可以共存。
两种导出模式区分
命名导出(上面全部示例)
export { a, b };
// 导入时必须严格匹配名称
import { a, b } from './xxx.js'
默认导出 export default
一个模块最多只能有一个默认导出
// module.js
export default function(){
console.log('默认函数');
}
// app.js,导入名称自定义,不需要大括号
import fn from './module.js'
区别:
命名导出:多个,导入需要{};
默认导出:单个,导入不需要{}。
export * 整体转发(模块代理)
用于中转其它模块接口,常用于聚合模块
// index.js 汇总所有接口向外暴露
export * from './user.js'
// 只转发指定变量
export { getName } from './user.js'