ESModule.js
模块化:在解决一些复杂问题的同时,按照一种分类的思想,把问题分解成若干个小模块功能,然后逐个实现这些小模块
模块化系统应该做什么?
- 封装定义一个模块
- 导出内容供其他模块使用
- 能够导入其他模块的内容
CommonJS Node.js 的模块化规范 :module.exports / require()
AMD require.js 异步模块化标准
ESModule ES6 新增的模块化规范
- 一个 js 文件就是一个模块
- export 关键字 导出
- import 关键字 导入
1. export 导出
单个导出
// export 关键字用于指定模块导出的内容
// 单个导出
export var name = 'mabin';
export var age = 18;
export var job = 'FE';
export let x = 1;
export const y = 2;
export function sum(a, b) {
return a + b;
}
export class Teacher {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let ok = 100;
// 单个导出 export 变量声明语句;
批量导出
var name = 'mabin';
var age = 'age';
var job = 'FE';
let x = 1;
const y = 2;
function sum(a, b) {
return a + b;
}
class Teacher {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let ok = 100;
// 批量导出: export {要导出的变量}
export {name, age, job, x, y, sum, Teacher}
// 推荐使用批量导出的方式导出,可以很清晰的看出模块导出了哪些东西;
2. export
import 关键字用来从其他模块中导入内容,导入注意事项:
- import {变量} from ‘带路径的模块文件’
- 模块没有导出的的变量不能导入
- html 在引入模块化的 js 文件时,script 标签上要写 type = “module”
例子:
// 导入 4-export.js
import {name, age, job, x, y, sum, Teacher} from "./4-export.js";
写在 import 后面的花括号中的都是变量,自己声明的变量不能喝花括号里面的重名
as 关键字
在导入的时候给导出的变量重命名:as 关键字
语法:import {原名 as 新名字} from 模块
import {Teacher as T} from "./5-export.js";
// console.log(Teacher); 重命名之后 Teacher 就不能用了
console.log(T);
// 按需导入,不需要全部导入
全部导入
全部导入:把模块中导出的内容全部导入进来
import * as obj from './5-export.js'; // 把 5-export.js 中导出的内容全部导入,放到 obj 中,obj 是一个对象;obj 是一个变量,符合变量命名的变量都行;
console.log(obj); // obj 是一个对象,对象中的属性名是导出时的变量名,属性的值是导出时变量所代表的值;
console.log(obj.sum(3, 4));
默认导出
在前面的例子中,我们想要导入,必须知道导出的时候名字都是什么,如果不知道没办法导入;ESModule 提供了一个默认导出,其他模块在导入的时候可以不关心导出的名字是什么
export default function sum(a, b) {
return a + b;
}
一个模块的默认导出只能有一个,多了要报错
// export default function minus(a, b) {
// return a - b;
// }
console.log(`1111`);
import aaa from './9-export-default.js';
console.log(aaa);
// 如果模块是默认导出的,导入的时候不要写花括号,导入时的名字随意写;
3. 动态导入
动态导入:import 只能是同步的,模块导入是静态的,发生在 js 代码执行之前,而且只能写在顶层作用域中;但是有一些场景需要动态导入模块;此时我们需要用 import()方法
import() 方法支持动态导入,返回一个 Promise 实例,可以直接 .then,then 的第一个回调收到的参数就是模块中的内容
动态导入就是想在什么地方导入就在什么地方导入,想什么时候导入就什么时候导入
// 3s 后导入
setTimeout(() => {
import('./5-export.js').then((res) => {
console.log(res);
})
}, 3000);
let ran = Math.round(Math.random() * (10 - 0) + 0);
console.log(ran);
// 如果随机数大于5去加载 a 模块,否则加载 b 模块
if (ran > 5) {
import('./a.js').then((a) => console.log(a))
} else {
import('./b.js').then((b) => console.log(b));
}
// 动态导入模块的场景:
// 1. 按需加载,如点击或者滑动的时候去加载;
// 2. 条件加载,条件为 true 的时候加载 a 模块,否则加载 b 模块
// 3. 模块的路径是动态的,例如路径是通过 ajax 从服务端获取的
// 动态加载多个模块: Promise.all([])
Promise.all([
import('./a.js'),
import('./b.js')
]).then((arr) => {
console.log('L 39');
console.log(arr);
});
// import() 和 async / await
// import() 会返回 promise 对象
async function getM() {
let A = await import('./a.js');
let B = await import('./b.js');
return [A, B]
}
getM().then((res) => {
console.log('L51');
console.log(res);
});
// a 模块
export let a = 'A';
// b 模块
export let b = 'B';