ESModule.js

模块化:在解决一些复杂问题的同时,按照一种分类的思想,把问题分解成若干个小模块功能,然后逐个实现这些小模块

模块化系统应该做什么?

  1. 封装定义一个模块
  2. 导出内容供其他模块使用
  3. 能够导入其他模块的内容

CommonJS Node.js 的模块化规范 :module.exports / require()

AMD require.js 异步模块化标准

ESModule ES6 新增的模块化规范

  1. 一个 js 文件就是一个模块
  2. export 关键字 导出
  3. import 关键字 导入

1. export 导出

单个导出

  1. // export 关键字用于指定模块导出的内容
  2. // 单个导出
  3. export var name = 'mabin';
  4. export var age = 18;
  5. export var job = 'FE';
  6. export let x = 1;
  7. export const y = 2;
  8. export function sum(a, b) {
  9. return a + b;
  10. }
  11. export class Teacher {
  12. constructor(name, age) {
  13. this.name = name;
  14. this.age = age;
  15. }
  16. }
  17. let ok = 100;
  18. // 单个导出 export 变量声明语句;

批量导出

  1. var name = 'mabin';
  2. var age = 'age';
  3. var job = 'FE';
  4. let x = 1;
  5. const y = 2;
  6. function sum(a, b) {
  7. return a + b;
  8. }
  9. class Teacher {
  10. constructor(name, age) {
  11. this.name = name;
  12. this.age = age;
  13. }
  14. }
  15. let ok = 100;
  16. // 批量导出: export {要导出的变量}
  17. export {name, age, job, x, y, sum, Teacher}
  18. // 推荐使用批量导出的方式导出,可以很清晰的看出模块导出了哪些东西;

2. export

import 关键字用来从其他模块中导入内容,导入注意事项:

  1. import {变量} from ‘带路径的模块文件’
  2. 模块没有导出的的变量不能导入
  3. html 在引入模块化的 js 文件时,script 标签上要写 type = “module”

例子:

  1. // 导入 4-export.js
  2. import {name, age, job, x, y, sum, Teacher} from "./4-export.js";

写在 import 后面的花括号中的都是变量,自己声明的变量不能喝花括号里面的重名

as 关键字

在导入的时候给导出的变量重命名:as 关键字
语法:import {原名 as 新名字} from 模块

  1. import {Teacher as T} from "./5-export.js";
  2. // console.log(Teacher); 重命名之后 Teacher 就不能用了
  3. console.log(T);
  4. // 按需导入,不需要全部导入

全部导入

全部导入:把模块中导出的内容全部导入进来

  1. import * as obj from './5-export.js'; // 把 5-export.js 中导出的内容全部导入,放到 obj 中,obj 是一个对象;obj 是一个变量,符合变量命名的变量都行;
  2. console.log(obj); // obj 是一个对象,对象中的属性名是导出时的变量名,属性的值是导出时变量所代表的值;
  3. console.log(obj.sum(3, 4));

默认导出

在前面的例子中,我们想要导入,必须知道导出的时候名字都是什么,如果不知道没办法导入;ESModule 提供了一个默认导出,其他模块在导入的时候可以不关心导出的名字是什么

  1. export default function sum(a, b) {
  2. return a + b;
  3. }
  4. 一个模块的默认导出只能有一个,多了要报错
  5. // export default function minus(a, b) {
  6. // return a - b;
  7. // }
  8. console.log(`1111`);
  9. import aaa from './9-export-default.js';
  10. console.log(aaa);
  11. // 如果模块是默认导出的,导入的时候不要写花括号,导入时的名字随意写;

3. 动态导入

动态导入:import 只能是同步的,模块导入是静态的,发生在 js 代码执行之前,而且只能写在顶层作用域中;但是有一些场景需要动态导入模块;此时我们需要用 import()方法

import() 方法支持动态导入,返回一个 Promise 实例,可以直接 .then,then 的第一个回调收到的参数就是模块中的内容

动态导入就是想在什么地方导入就在什么地方导入,想什么时候导入就什么时候导入

  1. // 3s 后导入
  2. setTimeout(() => {
  3. import('./5-export.js').then((res) => {
  4. console.log(res);
  5. })
  6. }, 3000);
  7. let ran = Math.round(Math.random() * (10 - 0) + 0);
  8. console.log(ran);
  9. // 如果随机数大于5去加载 a 模块,否则加载 b 模块
  10. if (ran > 5) {
  11. import('./a.js').then((a) => console.log(a))
  12. } else {
  13. import('./b.js').then((b) => console.log(b));
  14. }
  15. // 动态导入模块的场景:
  16. // 1. 按需加载,如点击或者滑动的时候去加载;
  17. // 2. 条件加载,条件为 true 的时候加载 a 模块,否则加载 b 模块
  18. // 3. 模块的路径是动态的,例如路径是通过 ajax 从服务端获取的
  19. // 动态加载多个模块: Promise.all([])
  20. Promise.all([
  21. import('./a.js'),
  22. import('./b.js')
  23. ]).then((arr) => {
  24. console.log('L 39');
  25. console.log(arr);
  26. });
  27. // import() 和 async / await
  28. // import() 会返回 promise 对象
  29. async function getM() {
  30. let A = await import('./a.js');
  31. let B = await import('./b.js');
  32. return [A, B]
  33. }
  34. getM().then((res) => {
  35. console.log('L51');
  36. console.log(res);
  37. });
  38. // a 模块
  39. export let a = 'A';
  40. // b 模块
  41. export let b = 'B';