当前位置: 首页 > news >正文

JavaScript 15章:模块化编程

在现代软件开发中,模块化编程是一种非常重要的实践,它可以帮助开发者组织代码,提高代码的复用性和可维护性。以下是关于模块化编程的一些关键知识点和实战案例:

第15章:模块化编程

模块的概念

模块是指将一组相关的函数、类或变量封装在一起,作为一个独立的单元进行组织和管理。模块化的优点包括但不限于:

  • 代码复用:模块可以被多个程序或模块重复使用。
  • 隔离性:模块之间的依赖关系清晰,降低了全局作用域污染的风险。
  • 可维护性:每个模块关注于解决特定的问题,使代码更容易理解和维护。
CommonJS 规范

CommonJS 是一种早期的JavaScript模块化规范,主要用于Node.js环境中。它的核心特性包括:

  • 模块导出:使用module.exportsexports对象来导出模块成员。
  • 模块导入:使用require函数来导入其他模块。

示例

// example.js
module.exports = {greet: function(name) {return `Hello, ${name}!`;}
};
// app.js
const example = require('./example.js');
console.log(example.greet('Alice'));
ES6 Modules

ES6 Modules(也称为ECMAScript Modules)是现代浏览器支持的一种模块化标准。相较于CommonJS,ES6 Modules提供了更简洁的语法,并且支持静态分析,这有助于工具链(如打包工具)的优化。

  • 导出:使用export关键字。
  • 导入:使用import关键字。

示例

// example.js
export function greet(name) {return `Hello, ${name}!`;
}
// app.js
import { greet } from './example.js';
console.log(greet('Alice'));
实战案例:模块化项目结构

假设我们要构建一个简单的Web应用,该应用包括用户认证、数据获取等功能。我们可以按照如下结构组织代码:

project/
├── src/
│   ├── index.html
│   ├── js/
│   │   ├── main.js
│   │   ├── auth/
│   │   │   ├── login.js
│   │   │   ├── logout.js
│   │   ├── api/
│   │   │   ├── fetchData.js
│   │   ├── utils/
│   │   │   ├── helpers.js
│   ├── css/
│   │   └── styles.css
└── package.json

在这个结构中:

  • src/js/main.js 是主入口文件,它将导入其他模块并启动应用。
  • src/js/auth 目录包含了与用户认证相关的模块。
  • src/js/api 目录包含了与数据获取相关的模块。
  • src/js/utils 目录包含了通用的辅助函数。

示例代码

// src/js/auth/login.js
export function login(username, password) {// 模拟登录逻辑console.log(`Logging in with username: ${username}`);return new Promise(resolve => setTimeout(resolve, 1000));
}// src/js/api/fetchData.js
export async function fetchData(url) {const response = await fetch(url);if (!response.ok) {throw new Error(`Could not fetch data: ${response.statusText}`);}return await response.json();
}// src/js/main.js
import { login } from './auth/login';
import { fetchData } from './api/fetchData';async function initApp() {try {await login('alice@example.com', 'password123');const data = await fetchData('/api/data');console.log(data);} catch (error) {console.error(error);}
}initApp();

在这个例子中,我们使用了ES6 Modules来组织代码。main.js作为主入口文件,导入了loginfetchData模块,并调用它们来初始化应用。这样的模块化结构使得代码更加清晰易读,并且易于扩展和维护。

总结

通过上述介绍,我们了解了模块化编程的基本概念,以及CommonJS和ES6 Modules这两种主要的模块化规范。通过实战案例,我们也看到了如何将模块化应用于实际项目中,从而提升代码的质量和可维护性。在实际开发中,可以根据项目的需求选择合适的模块化方案和技术栈。

好的,我们继续深入探讨模块化编程,并进一步扩展实战案例,以涵盖更多实用的细节和最佳实践。

继续实战案例:模块化项目结构

扩展模块功能

在前面的基础上,我们可以进一步扩展各个模块的功能,并引入更多的模块化元素,如错误处理、环境配置、样式管理等。

新增模块:错误处理

错误处理是模块化编程中的一个重要方面,尤其是在处理网络请求或其他异步操作时。我们可以创建一个专门的错误处理模块来统一处理应用中的错误。

// src/js/utils/errorHandler.js
export class AppError extends Error {constructor(message, statusCode) {super(message);this.statusCode = statusCode;this.isOperational = true;Error.captureStackTrace(this, this.constructor);}
}export function handleError(err, res) {if (err.isOperational) {res.status(err.statusCode).json({status: 'fail',message: err.message});} else {// 编程或未知错误console.error('ERROR', err);res.status(500).json({status: 'error',message: 'Something went wrong!'});}
}
新增模块:环境配置

在生产环境中,我们需要处理不同环境下的配置,例如API URL、环境变量等。可以通过创建一个配置模块来管理这些设置。

// src/js/config.js
export const config = {development: {apiUrl: 'http://localhost:3000/api'},production: {apiUrl: 'https://api.example.com'}
};// 根据环境变量选择配置
export const getConfig = () => {return process.env.NODE_ENV === 'production' ? config.production : config.development;
};
扩展主入口文件

现在,我们可以在主入口文件中引入新的模块,并使用它们来增强应用的功能。

// src/js/main.js
import { login } from './auth/login';
import { fetchData } from './api/fetchData';
import { AppError, handleError } from './utils/errorHandler';
import { getConfig } from './config';
import { showNotification } from './utils/notification'; // 假设这是一个用于显示通知的模块const config = getConfig();async function initApp() {try {await login('alice@example.com', 'password123');// 使用配置中的API URLconst data = await fetchData(`${config.apiUrl}/data`);console.log(data);// 成功后显示通知showNotification('Data fetched successfully!', 'success');} catch (error) {// 失败时使用错误处理模块handleError(new AppError(error.message, 400), {});showNotification('Failed to fetch data.', 'error');}
}initApp();
管理样式

对于前端应用,样式管理也是重要的一环。可以将样式分离到单独的CSS文件中,并通过模块化的方式引用。

/* src/css/styles.css */
.notification {position: fixed;top: 20px;right: 20px;padding: 10px;border-radius: 5px;z-index: 1000;
}.notification.success {background-color: #4CAF50;color: white;
}.notification.error {background-color: #f44336;color: white;
}

在HTML中引用样式文件:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Module-Based Web Application</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>User Information</h1>
<button id="load-data" onclick="initApp()">Load User Data</button>
<div id="notifications"></div>
<script src="/main.js" type="module"></script>
</body>
</html>
通知模块

我们还可以添加一个简单的通知模块来显示成功或错误的消息。

// src/js/utils/notification.js
export function showNotification(message, type) {const notificationsDiv = document.getElementById('notifications');const notification = document.createElement('div');notification.className = `notification ${type}`;notification.textContent = message;notificationsDiv.appendChild(notification);// 自动移除通知setTimeout(() => {notificationsDiv.removeChild(notification);}, 3000);
}

总结

通过以上步骤,我们进一步完善了模块化项目的结构,并添加了更多实用的功能:

  • 错误处理模块:集中处理应用中的错误,提供一致的错误响应。
  • 环境配置模块:根据环境变量选择不同的配置,便于部署到不同的环境。
  • 样式管理:分离CSS样式,并通过模块化的方式引用。
  • 通知模块:提供简单的通知系统,用于显示成功或错误消息。

这些改进使得应用更加健壮、灵活,并且易于维护。在实际项目中,可以根据具体的业务需求进一步扩展和完善模块化架构。模块化编程不仅可以提高代码质量,还能促进团队协作和代码复用,是现代软件开发不可或缺的一部分。

好的,我们可以进一步深入探讨模块化编程,并扩展之前的案例,使之更加完整和实用。接下来,我们将讨论如何在模块之间共享状态、利用Webpack进行模块打包、以及如何编写测试用例来验证模块的功能。

共享状态与状态管理

在大型应用中,模块之间常常需要共享某些状态,例如用户的登录状态、全局配置等。我们可以使用一个状态管理库,如Redux或MobX,来集中管理这些状态。这里我们简单展示如何使用一个简单的状态管理机制来共享状态。

状态管理模块
// src/js/state/index.js
export const initialState = {isLoggedIn: false,userData: null
};export const setState = (state) => {Object.assign(initialState, state);
};export const getState = () => initialState;
更新状态

login.js中,我们可以更新状态来反映用户的登录状态。

// src/js/auth/login.js
import { login as doLogin, logout as doLogout } from './authService';
import { setState } from '../state';export async function login(username, password) {try {const user = await doLogin(username, password);setState({ isLoggedIn: true, userData: user });return user;} catch (error) {throw new Error('Login failed.');}
}export async function logout() {await doLogout();setState({ isLoggedIn: false, userData: null });
}

使用Webpack进行模块打包

在实际开发中,通常会使用构建工具来打包和优化模块。Webpack是一个流行的模块打包器,可以将所有模块及其依赖项打包成一个或多个优化过的文件。

安装Webpack及相关插件

如果你还没有安装Webpack,可以使用npm安装:

npm install --save-dev webpack webpack-cli
创建Webpack配置文件

创建一个名为webpack.config.js的文件,配置Webpack来处理ES6模块。

// webpack.config.js
const path = require('path');module.exports = {entry: './src/js/main.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist'),clean: true},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env']}}}]},mode: 'development', // 或者 'production'devtool: 'inline-source-map' // 只在开发模式下使用
};
编译模块

运行Webpack来编译你的模块:

npx webpack

这将会把所有的模块打包成一个bundle.js文件。

编写测试用例

在模块化编程中,编写测试用例非常重要,可以确保模块按预期工作。我们可以使用Jest框架来编写和运行测试。

安装Jest
npm install --save-dev jest @babel/preset-env @babel/core babel-jest
创建测试文件

login.js创建一个测试文件login.test.js

// src/js/__tests__/login.test.js
import { login, logout } from '../auth/login';
import { getState } from '../state';describe('Auth Module', () => {it('should log in the user and update state', async () => {const mockUser = { name: 'Alice', email: 'alice@example.com' };global.fetch = jest.fn().mockImplementationOnce(() => {return Promise.resolve({json: () => Promise.resolve(mockUser)});});await login('alice@example.com', 'password123');expect(getState()).toEqual({ isLoggedIn: true, userData: mockUser });});it('should log out the user and update state', async () => {global.fetch = jest.fn().mockImplementation(() => {return Promise.resolve({ok: true});});await logout();expect(getState()).toEqual({ isLoggedIn: false, userData: null });});
});

总结

通过以上步骤,我们进一步扩展了模块化项目,使其更加实用和健壮:

  • 状态管理:使用简单的状态管理机制来共享状态。
  • Webpack配置:使用Webpack来打包和优化模块。
  • 测试用例:编写测试用例来验证模块的功能。

这些改进使得应用不仅更加模块化,而且易于测试和维护。在实际项目中,可以根据具体情况选择合适的工具和技术栈,进一步完善和优化模块化架构。模块化编程能够帮助开发者更好地组织代码,提高开发效率,同时保证代码质量和可维护性。

相关文章:

JavaScript 15章:模块化编程

在现代软件开发中&#xff0c;模块化编程是一种非常重要的实践&#xff0c;它可以帮助开发者组织代码&#xff0c;提高代码的复用性和可维护性。以下是关于模块化编程的一些关键知识点和实战案例&#xff1a; 第15章&#xff1a;模块化编程 模块的概念 模块是指将一组相关的…...

qt creator 开发环境的安装

1.找官网 官网地址&#xff1a;Installation | Qt Creator Documentation 点 Parent Directory 继续点 Parent Directory 点 archive/ 2.下载在线安装器 点 online_ainstallers 选择在线安装器版本 选择对应版本后进入下载列表&#xff0c;根据自己的系统选择下载。 下载后…...

Xilinx远程固件升级(二)——STARTUPE2原语的使用

通过&#xff08;一&#xff09;可以看出&#xff0c;对于远程固件升级实际上是通过调用flash不同区域的bit实现&#xff0c;通过golden image和update image共同保障了系统的稳定性。在项目中如果将flash的时钟直接绑定FPGA后进行约束&#xff0c;在综合编译时是无法通过的。这…...

DynamicExpresso

DynamicExpresso 动态Expression 安装包&#xff1a;DynamicExpresso.Core Student.cs public class Student { public int Age { get; set; } public string Name { get; set; } public void Hello() { Con…...

从Naive RAG到Agentic RAG:基于Milvus构建Agentic RAG

检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;作为应用大模型落地的方案之一&#xff0c;通过让 LLM 获取上下文最新数据来解决 LLM 的局限性。典型的应用案例是基于公司特定的文档和知识库开发的聊天机器人&#xff0c;为公司内部人员快速检索内部…...

Linux 环境chrony设置服务器间时间同步一致

服务器&#xff1a; master01: slave02: slave03: 安装chrony安装&#xff1a; yum -y install chrony 设置以master01为时间服务器&#xff0c;其他服务器同步master01时间 master01的chrony.conf配置: server ntp1.aliyun.com iburst allow all local stratum 10重启ch…...

MetaCTO确认将放弃QuestPro2及轻量化头显正在开发中

MetaCTO确认将放弃QuestPro2及轻量化头显正在开发中 随着虚拟现实(VR)和增强现实(AR)技术的不断发展&#xff0c;越来越多的公司开始关注这个领域。其中&#xff0c;QuestPro2是一款备受关注的头戴式显示器&#xff0c;由MetaCTO公司开发。然而&#xff0c;最近MetaCTO公司宣布…...

深度学习 .exp()

在 MXNet 中&#xff0c;.exp() 是 ndarray 对象的方法&#xff0c;用于计算数组中每个元素的指数&#xff08;e 的幂&#xff09;。此方法适用于所有类型的 ndarray&#xff0c;并返回一个新的数组&#xff0c;其中每个元素都是相应输入元素的指数。 语法 ndarray.exp() 参…...

从数据管理到功能优化:Vue+TS 项目实用技巧分享

引言 在项目开发过程中&#xff0c;优化用户界面和完善数据处理逻辑是提升用户体验的重要环节。本篇文章将带你一步步实现从修改项目图标、添加数据、优化日期显示&#xff0c;到新增自定义字段、调整按钮样式以及自定义按钮跳转等功能。这些操作不仅提升了项目的可视化效果&am…...

SSD |(六)FTL详解(上)

文章目录 &#x1f4da;FTL综述&#x1f4da;映射管理&#x1f407;映射的种类&#x1f407;映射的基本原理&#x1f407;HMB&#x1f407;映射表写入 &#x1f4da;FTL综述 当SSD所使用的主控和闪存确定后&#xff0c;FTL算法的好坏将直接决定SSD在性能、可靠性、耐用性等方面…...

程序报错:ModuleNotFoundError: No module named ‘code.utils‘; ‘code‘ is not a package

程序报错内容&#xff1a; Traceback (most recent call last): File "code/nli_inference/veracity_prediction.py", line 10, in <module> from code.utils.data_loader import read_json ModuleNotFoundError: No module named code.utils; code is …...

【closerAI ComfyUI】电商模特一键换装解决方案来了!细节到位无瑕疵!再加上flux模型加持,这个工作流不服不行!

不得了了兄弟们。这应该是电商界的福音&#xff0c;电商模特一键换装解决方案来了&#xff01;细节到位无瑕疵&#xff01;再加上flux模型加持&#xff0c;这个工作流不服不行&#xff01; 这期我们主要讨论如何使用stable diffusion comfyUI 制作完美无瑕疵的换装工作流。** …...

【优选算法篇】编织算法的流动诗篇:滑动窗口的轻盈之美

文章目录 C 滑动窗口详解&#xff1a;基础题解与思维分析前言第一章&#xff1a;热身练习1.1 长度最小的子数组解法一&#xff08;暴力求解&#xff09;解法二&#xff08;滑动窗口&#xff09;滑动窗口的核心思想图解分析滑动窗口的有效性时间复杂度分析易错点提示 1.2 无重复…...

Linux 常用打包和压缩格式命令(tar tar.gz tar.bz2 tar.xz zip)

Linux 常用打包和压缩格式命令&#xff08;tar tar.gz tar.bz2 tar.xz zip&#xff09; 常用压缩包&#xff1a; tar 仅打包&#xff0c;不压缩。 gzip 使用DEFLATE算法进行压缩,通常用于.gz或.tar.gz文件。 bzip2 使用Burrows-Wheeler算法进行压缩,通常用于.bz2或.tar.bz2文件…...

Scala入门基础(12)抽象类

抽象类&#xff0c;制定标准&#xff0c;不要求去具体实现 包含了抽象方法的类就是抽象类。抽象方法只是有方法名&#xff0c;没有具体方法体的方法 定义抽象类要用abstract&#xff08;抽象&#xff09;关键字 用智能驾驶技术举例&#xff1a;演示&#xff09…...

unity静态批处理

unity静态批处理 静态批处理要求和兼容性渲染管线兼容性 使用静态批处理在构建时进行静态批处理在构建时执行静态批处理的步骤&#xff1a; 在运行时进行静态批处理性能影响 静态批处理 静态批处理是一种绘制调用批处理方法&#xff0c;它将不移动的网格组合在一起&#xff0c…...

python项目实战——下载美女图片

python项目实战——下载美女图片 文章目录 python项目实战——下载美女图片完整代码思路整理实现过程使用xpath语法找图片的链接检查链接是否正确下载图片创建文件夹获取一组图片的链接获取页数 获取目录页的链接 完善代码注意事项 完整代码 import requests import re import…...

git分布式版本控制系统命令介绍、功能作用案例、子模块等知识点总结

Git是一个分布式版本控制系统&#xff0c;广泛用于软件开发中。以下是Git的常用命令、功能、作用以及一些使用案例的详细介绍。 Git 基本命令 配置 git config: 配置用户信息&#xff0c;如用户名和电子邮件。 git config --global user.name "Your Name"git confi…...

第八课:Python学习之循环

循环 目标 程序的三大流程while 循环基本使用break 和 continuewhile 循环嵌套 01. 程序的三大流程 在程序开发中&#xff0c;一共有三种流程方式&#xff1a; 顺序 —— 从上向下&#xff0c;顺序执行代码分支 —— 根据条件判断&#xff0c;决定执行代码的 分支循环 —— …...

设计模式——建造者模式(5)

一、写在前面 创建型模式 单例模式工厂方法模式抽象工厂模式原型模式建造者模式 结构型模式行为型模式 二、介绍 建造者模式主要在以下场景中得到应用&#xff1a; 当需要创建的对象具有复杂的内部结构&#xff0c;且包含多个属性时&#xff0c;建造者模式可以将对象的构建…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...