JavaScript 模块化

69 阅读5分钟

一、模块化认识

事实上模块化开发最终的目的是将程序划分成一个个小的结构,这个结构中编写属于自己的逻辑代码,有自己的作用域,不会影响到其他的结构,这个结构可以将自己希望暴露的变量、函数、对象等导出给其结构使用,也可以通过某种方式,导入另外结构中的变量、函数、对象等。

注:早期没有模块化带来了很多的问题:比如命名冲突的问题。

一个文件就是一个模块,不应该在一个文件里写多个模块(就算这个模块只有一行代码,他也独立成件)。

1、模块化规范

注:ES6(2015)推出了模块化方案

AMD

CMD

CommonJS 简称为 CJS

ES Modules

注:CommonJS 主要在 node 中使用,AMD、CMD 基本上退出舞台,ES Modules 是主流。

2、没有模块化时,实现模块化代码

demo

二、CommonJS

1、CommonJS 规范和 Node 关系

CommonJS 是一个规范,最初提出来是在浏览器以外的地方使用,并且当时被命名为 ServerJS,后来为了 体现它的广泛性,修改为 CommonJS,平时我们也会简称为 CJS。

1)Node 是 CommonJS 在服务器端一个具有代表性的实现

2)Browserify 是 CommonJS 在浏览器中的一种实现

3)webpack 打包工具具备对CommonJS 的支持和转换

4)在 Node 中每一个 js 文件都是一个单独的模块

5)模块中包括 CommonJS 规范的核心变量:exports、module.exports、require

6)CommonJS 中导出使用:exports 和 module.exports

7)CommonJS 中导入使用:require 函数

2、CommonJS 案例

1)module.exports

image-20240205025917892

理解:

image-20240205235253940

2)exports

image-20240206001851394

注:最后导出的时候,一定用的是 module.exports。

3)require

文档

require 是一个函数。

① 导入格式

require(X)

② require 导入核心模块

const path = require("path");
const fs = require("fs");

文档

③ 导入文件

查找顺序:X.js > X.json > X.node文件 > 目录 > X/index.js > X/index.json > X/index.node文件

如果没有找到,那么报错:not found。

④ 不是一个X(没有路径),并且X不是一个核心模块的查找顺序

console.log(module);

image-20240206005411230

3、模块加载过程

① 模块在被第一次引入时,模块中的js代码会被运行一次,因为只要 require 了,文件里面的代码就会加载都缓存中去了

② 模块被多次引入时,会缓存,最终只加载(运行)一次(每个模块对象 module 都有一个属性 loaded,用来记录是否加载过)

③ 模块不建议循环引用

④ Node 采用的是深度优先算法

4、缺点

CommonJS 加载模块是同步的

同步的意味着只有等到对应的模块加载完毕,当前模块中的内容才能被运行,这个在服务器不会有什么问题,因为服务器加载的js文件都是本地文件,加载速度非常快;但是浏览器加载 js 文件需要先从服务器将文件下载下来,之后再加载运行,那么采用同步的就意味着后续的js代码都无法正常运行,即使是一些简单的 DOM 操作;所以使用 CommonJS 的时候,都是用 webpack转成浏览器可以直接执行的代码(早期为了可以在浏览器中使用模块化,通常会采用 AMD 或 CMD,目前已经放弃)。

三、AMD 😅

1、认识

1)AMD 全称 Asynchronous Module Definition(异步模块定义)的缩写

2)AMD 异步加载模块

3)AMD 规范早于 CommonJS,但是 CommonJS 目前依然在被使用,而AMD使用的较少了

2、实现

AMD 实现的比较常用的库是 require.jscurl.js

require.js 使用案例:

1)下载 require.js

2)使用

image-20240206015941362

demo

四、CMD 😅

1、认识

1)CMD 是 Common Module Definition(通用模块定义)的缩写

2)采用了异步加载模块,但是它将 CommonJS 的优点吸收了过来

2、实现

CMD 实现的比较常用的库是 SeaJS

SeaJS 使用案例:

1)下载 SeaJS

2)使用

image-20240206022803210

demo

五、ES Module 💡

MDN | JavaScript 模块

1、认识

1)采用编译期的静态分析,并且也加入了动态引用的方式

2)块采用export和import关键字来实现模块化

3)采用ES Module将自动采用严格模式:use strict

2、基础使用

image-20240206024019095

demo

3、导出方式

/**
 * 导出的第一种方式
 */
export const name1 = "我是 name1";

/**
 * 导出的第二种方式
 */
const name2 = "我是 name2";
export { // 里面可写多个
    name2
};

/**
 * 导出的第三种方式(起别名)
 * 不常用
 */
const name3 = "我是 name3";
export { // 里面可写多个
    name3 as name3Alias
};

image-20240206025759920

demo

4、导入方式

/**
 * 1、普通导入
 */
/*
import {
    name1,
    name2,
    name3Alias
} from "./test.js"; // 必须加 ”.js“

console.log(name1);
console.log(name2);
console.log(name3Alias);
*/
/**
 * 2、起别名(导出时起别名的情况很少,一版都是在这起别名)
 */
/*
import {
    name1 as name1Alias,
    name2 as name2Alias,
    name3Alias as name3
} from "./test.js";

console.log(name1Alias);
console.log(name2Alias);
console.log(name3);
 */
/**
 * 3、将导入的内容放到一个标识符中
 * 语法:import * as 名字 from './test.js';
 */
import * as all from './test.js';

console.log(all);
console.log(all.name1);
console.log(all.name2);
console.log(all.name3Alias);

image-20240206030553646

demo

5、混合使用

/**
 * 导入导出结合使用
 * 代码规范:
 * 在这统一出口
 * 使用的时候,只需要定位到这个文件就好
 */

/**
 * 第一种导出方式
 */
/*
import {
    add,
    reduce
} from './test-01.js';
import {
    formattedDate
} from "./test-02.js";

export {
    add,
    reduce,
    formattedDate
};
 */

/**
 * 第二种导出方式(推荐)
 * 简化了上面的代码
 */
/*
export {
    add,
    reduce
} from './test-01.js';
export {
    formattedDate
} from "./test-02.js";
*/

/**
 * 第三种导出方式
 * 只有当前文件中所有的方法都导出时使用,负责不要使用
 */
export * from './test-01.js';
export * from "./test-02.js";

image-20240206032702639

demo

6、default

image-20240206034507885

demo

7、export default 🔍

当文件夹中文件全是 export default 导出时,统一出口处的写法规范。

image-20240206041123768

demo

8、import 函数

import 导入的文件解析完之前,他下面的代码都是不会运行的。

希望 import {标识符列表} from '模块'; 异步解析的方法:

image-20240206035542957

9、解析流程

文档

十、CommonJS 和 ES Module 混合使用

注:① 浏览器中不可以;

② node 中可以;

③ webpack 中可以。

基于 webpack demo