模块化开发是一种在软件开发中广泛采用的方法,它将复杂的系统拆分为独立的模块,每个模块负责特定的功能或任务。通过模块化开发,开发人员可以将代码组织成可重用、可维护和可测试的单元,提高开发效率和代码质量。模块化开发的核心思想是将功能划分为独立的模块,每个模块具有清晰的接口和定义的功能,模块之间通过明确定义的接口进行通信和交互。这种方式使得团队成员可以并行开发不同的模块,减少了开发过程中的耦合性和冲突,并提高了代码的可维护性和可扩展性。常见的模块化开发规范包括CommonJS、AMD和ES Modules等,它们提供了统一的模块定义和加载机制,使得模块可以在不同的环境中共享和重用。模块化开发还促进了代码的可测试性,通过对每个模块进行单独的单元测试,可以更容易地发现和修复潜在的问题。然而,模块化开发也需要注意模块之间的依赖管理和版本控制,避免出现冗余的代码和不必要的依赖关系。因此,在进行模块化开发时,需要仔细规划模块的划分和接口设计,并结合最佳实践进行模块的组织和管理。
一、开发方式的演变
- 最早:一个 js 文件
-
- 每一个 html 文件对应一个 js 文件
- 后来:把一个项目内部的重复功能提取出来
-
- 写成一个单独的 js 文件
- 再后来:决定按照功能拆分出一个一个的文件
-
- a.js:专门做顶部导航栏各种功能
- b.js:专门做二级菜单
- c.js:专门做搜索引擎
- d.js:左侧边栏
- e.js:轮播图
- 最后在每一个页面准备一个整合的 js 文件,在引入这个整合的js文件的
script
标签中添加一个type="module"
属性 - 就是专门用来组合这个页面使用了多少个 js 文件模块
- 此时, 我们管每一个 js 文件叫做一个 模块
-
- 页面的完整功能, 就是由一个一个的模块来完成的
二、什么是模块化开发
- 模块化开发:是一种项目的构架模式,这种构架模式让 js 代码重用性变得非常高,让项目构架的一些复杂问题全部得以解决。
-
- 例如,一个html文件内不会再出现多个script标签,我们只要用一个script标签引入整合后的文件就可以了。
- 一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块
- 模块化开发的特点:
-
- 为了减少系统耦合度,提高内聚,减少资源依赖
- 便于维护,功能复用性更强
- 解决独立作用域、依赖管理、api暴露、按需加载与执行、安全合并等问题
三、常见的模块化规范
- AMD规范:第三方规范,依赖前置,规范化文件:require.js。
-
- 特点 : 前期消耗网络资源大,后期运行效率高
- 参考文档
- CMD规范:第三方规范,按需加载,规范化文件:sea.js。
-
- 特点:整个执行消耗曲线比较平缓
- CommonJS规范:Node.js的官方模块化规范
- ES6规范:ECMAScript的官方模块化规范
四、ES6模块化规范
- ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
- ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
4.1 使用环境:
-
- 使用了ES6模块化规范的页面必须处于服务器内
- VSCode的服务器插件:
Live Server
,安装(install),重启VSCode,在底部状态栏,点击go Live
,启动服务器 - 在html文件中,右键选择
open with live server
- 注意:引入使用了ES6模块规范的js文件的
script
标签,需添加type="module"
属性
4.2 注意事项
-
- 每一个 js 文件,都是一个独立的文件作用域
- 该文件内的所有变量和方法,都只能在这个文件内使用
4.3 ES6模块化语法
- 使用
export
关键字,规定模块的对外接口;使用import
关键字,输入其他模块提供的功能 - 导出语法
// 定义模块export语法:(module.js文件)
export const a = 10;
const b = 20;
export {b};
const c = "admin"
export {c as name};
// 或者
export {a,b,c};
export {a as num1, b as num2, c as name};
export default {num1:a, num2:b, name:c}
- 导入语法
// 导入模块import语法:(main.js文件)
import {a} from "./module.js";
import {b} from "./module.js";
import {c} from "./module.js";
import {a,b,c} from "./module.js";
import {num1,num2,num3} from "./module.js";
// 或者
import {num1 as n1, num2 as n2, num3 as n3} from "./module.js";
import obj from "./module.js";
-
注意:
-
export
和import
关键字,只能存在于顶层作用域内,不能存在局部或块级作用域- 在ES6的所有语法中,所有语法自动处在严格模式下
export
是声明关键字,声明一个对外接口export
声明的接口必须和模块内部的变量建立一一对应的关系export
声明的接口与对应的值是动态绑定,即可以拿到模块内部实时修改的值export
和import
时,都可以使用as
关键字,重命名接口- 使用
default
关键字,设置默认接口,一个模块中只允许出现一次default
import
在使用接口时,必须将接口放在花括号内,除非export
暴露接口时使用了default
关键字import
加载的接口是只读的,不允许被修改,如果接口是对象,可以修改属性import
具有提升效果- 由于
import
是静态执行,所以不能使用表达式和变量 - 当
import
后没有接收接口,会执行整个模块文件 - 可以使用通配符
*
加载整个模块的接口(需要配合as
使用),返回一个模块对象
五、案例和练习
- 练习
-
- hello模块定义了一个函数,接收一个参数
- world模块定义了一个函数,在这个函数中执行hello模块的功能,并传入一个数据(从hi模块中获取)
- hi模块定义了函数,返回了数据
- 购物车
-
- 两个页面
-
-
- 商品列表:点击商品,添加购物车
- 购物车:展示之前添加的商品
-
-
-
-
- 数据渲染到视图
- 修改选中
- 修改数量
- 删除单个
- 计算单个商品的总价
- 全选
- 总数量
- 总价
- 删除全部
-
-
-
- 技术栈:本地存储,设计模式,模块化