从0开始学习JavaScript--JavaScript CommonJS 和 Node.js 模块系统

news2025/1/13 10:22:25

JavaScript 的模块系统是实现模块化开发的关键,而 CommonJS 规范及其在 Node.js 中的应用是其中最为突出的例子。本文将深入研究 JavaScript 中的 CommonJS 模块规范,解析其核心概念,并通过丰富的示例代码展示其在 Node.js 中的实际应用。

CommonJS 模块规范的基本概念

1 模块定义

CommonJS 规范通过 module.exports 导出模块,通过 require 导入模块。这种简单而直观的模块定义方式成为 Node.js 开发的基础。

// math.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

module.exports = {
  add,
  subtract
};
// app.js
const math = require('./math');

console.log(math.add(5, 3)); // 输出: 8
console.log(math.subtract(5, 3)); // 输出: 2

2 模块导入机制

Node.js 使用同步加载模块的方式,当 require 被调用时,它会阻塞代码的执行,直到模块加载完成。

// app.js
console.log('Start loading...');
const math = require('./math');
console.log('Module loaded.');

console.log(math.add(5, 3)); // 输出: 8

3 模块缓存

为了提高性能,Node.js 会缓存已加载的模块。如果一个模块已经被加载过,再次调用 require 不会重新执行模块代码,而是返回缓存的模块对象。

// app.js
console.log('Start loading...');
const math1 = require('./math');
console.log('Module loaded.');

console.log(math1.add(5, 3)); // 输出: 8

console.log('Start loading again...');
const math2 = require('./math');
console.log('Module loaded again.');

console.log(math2.add(5, 3)); // 输出: 8

CommonJS 模块的实际应用

1 文件系统操作

Node.js 中的核心模块 fs 提供了文件系统操作的能力。创建一个模块用于读取文件内容。

// fileReader.js
const fs = require('fs');

const readFile = (filePath) => {
  try {
    return fs.readFileSync(filePath, 'utf-8');
  } catch (error) {
    console.error(`Error reading file: ${error.message}`);
    return null;
  }
};

module.exports = {
  readFile
};
// app.js
const fileReader = require('./fileReader');

const content = fileReader.readFile('example.txt');
if (content) {
  console.log('File content:', content);
}

2 HTTP 服务器

Node.js 的 http 模块使得创建简单的 HTTP 服务器变得容易。以下示例展示了一个简单的 HTTP 服务器模块。

// httpServer.js
const http = require('http');

const startServer = (port, onRequest) => {
  const server = http.createServer(onRequest);
  server.listen(port, () => {
    console.log(`Server listening on port ${port}`);
  });
};

module.exports = {
  startServer
};
// app.js
const httpServer = require('./httpServer');

const onRequest = (request, response) => {
  response.writeHead(200, { 'Content-Type': 'text/plain' });
  response.write('Hello, Node.js!');
  response.end();
};

httpServer.startServer(3000, onRequest);

模块的进阶应用

1 模块的循环依赖

CommonJS 模块支持循环依赖,但需要注意避免死锁的情况。以下是一个循环依赖的例子。

// a.js
const b = require('./b');

console.log('Module A:', b.value);
exports.value = 'A';
// b.js
const a = require('./a');

console.log('Module B:', a.value);
exports.value = 'B';
// app.js
const a = require('./a');
const b = require('./b');

console.log('App:', a.value, b.value);

运行 app.js 会输出:

Module B: undefined
Module A: B
App: A B

2 动态导入模块

Node.js 支持动态导入模块的实验性特性。使用 import() 可以在运行时动态加载模块。

// dynamicImport.js
const dynamicImport = async (path) => {
  const module = await import(path);
  return module;
};

module.exports = {
  dynamicImport
};
// app.js
const dynamicImportModule = require('./dynamicImport');

(async () => {
  const math = await dynamicImportModule.dynamicImport('./math');
  console.log(math.add(5, 3)); // 输出: 8
})();

模块的异常处理

在 Node.js 中,模块加载过程中可能会发生异常。为了更好地处理异常,可以使用 try...catch 来捕获模块加载过程中的错误。

// errorModule.js
throw new Error('This is a module loading error.');
// app.js
try {
  const errorModule = require('./errorModule');
  console.log('Module loaded successfully.');
} catch (error) {
  console.error('Error loading module:', error.message);
}

模块的调试技巧

Node.js 提供了丰富的调试工具,可以帮助我们更容易地调试模块中的代码。使用 --inspect 参数启动 Node.js,并配合 Chrome DevTools,可以进行更方便的调试。

node --inspect app.js

打开 Chrome 浏览器并输入 chrome://inspect,即可连接到 Node.js 实例进行调试。

模块的单元测试

为了保证模块的质量和稳定性,进行单元测试是一种有效的方式。使用测试框架(如 Mocha、Jest)和断言库(如 Chai、assert)可以轻松进行模块单元测试。

// math.test.js
const { expect } = require('chai');
const { add, subtract } = require('./math');

describe('Math Module', () => {
  it('should add two numbers correctly', () => {
    expect(add(5, 3)).to.equal(8);
  });

  it('should subtract two numbers correctly', () => {
    expect(subtract(5, 3)).to.equal(2);
  });
});

运行测试:

mocha math.test.js

模块的发布与管理

当编写的模块越来越多时,如何进行有效的模块管理变得尤为重要。Node.js 使用 npm(Node Package Manager)作为包管理工具,通过 package.json 文件来定义和管理模块。

// package.json
{
  "name": "my-module",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "test": "mocha"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "chai": "^4.3.4",
    "mocha": "^9.0.3"
  }
}

模块的异步加载

除了同步加载模块外,Node.js 还支持异步加载模块。使用 require.resolve 方法可以获取模块的路径,再通过 require 异步加载模块。

// asyncModule.js
console.log('Async module is loaded.');

module.exports = {
  message: 'Hello from async module!'
};
// asyncApp.js
console.log('Start loading async module...');
require.resolve('./asyncModule', (resolvedPath) => {
  console.log('Async module path:', resolvedPath);
  const asyncModule = require(resolvedPath);
  console.log(asyncModule.message);
});
console.log('Async module loading...');

模块的热更新

在 Node.js 中,可以通过 module.hot 实现模块的热更新。这在开发阶段,不需要重启 Node.js 服务器,就能够应用代码的变化。

// hotUpdateModule.js
let message = 'Hello from hot update module!';

module.exports = {
  getMessage: () => message,
  setMessage: (newMessage) => {
    message = newMessage;
  }
};
// hotUpdateApp.js
const hotUpdateModule = require('./hotUpdateModule');

console.log('Original message:', hotUpdateModule.getMessage());

// 模拟代码变化
module.hot.accept('./hotUpdateModule', () => {
  console.log('Hot update detected!');
  console.log('Updated message:', hotUpdateModule.getMessage());
});

// 模拟代码变化后更新消息
setTimeout(() => {
  hotUpdateModule.setMessage('Updated message!');
}, 2000);

模块的安全性考虑

在实际开发中,需要关注模块的安全性。一些常见的安全性措施包括:

  • 使用 npm 包时,注意包的质量和安全性,避免使用过时或有漏洞的包。
  • 避免使用 eval 函数,以防止代码注入攻击。
  • 设置合适的权限,确保只有授权的用户可以访问敏感资源。

总结

JavaScript 的 CommonJS 模块规范及其在 Node.js 中的应用为开发者提供了强大的模块化开发能力。本文深入探讨了 CommonJS 模块规范的核心概念,并通过大量的示例代码展示了其在 Node.js 中的实际应用,包括异常处理、调试技巧、单元测试、模块的发布与管理、异步加载、热更新以及安全性考虑等方面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1274463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL核心知识点整理大全1-笔记

MySQL 是一种流行的关系型数据库管理系统,它是以C和C语言编写的,最初是由瑞典公司MySQL AB开发的,现在是由Oracle公司维护和支持。MySQL是开源软件,可在Windows、Linux、Mac OS、FreeBSD等各种操作系统上运行。MySQL的主要特点是速…

数字图像处理(实践篇)十四 图像金字塔

目录 一 图像金字塔 二 涉及的函数 三 实践 一 图像金字塔 在某些情况下,需要处理不同分辨率的(相同)图像。比如,在图像中搜索某些目标(比如人脸)的时候,不确定该目标在所述图像中会以多大的…

智能优化算法应用:基于象群算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于象群算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于象群算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.象群算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

HTML5+CSS3小实例:纯CSS实现文字组成肖像特效

实例:纯CSS实现文字组成肖像特效 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" conten…

Java SpringBoot Controller常见写法

文章目录 环境Controller调用脚本运行结果总结 环境 系统: windows 11 工具: java, idea, git bash Controller 接口常见有以下几种方式 其中&#xff1a; Tobj 调用脚本 我的是windows 系统&#xff0c;使用 git bash 窗口运行, 用 cmd 或者 power shell 会有问题 curl …

《合成孔径雷达成像算法与实现》_使用CS算法对RADARSAT-1数据进行成像

CSA 简介&#xff1a;Chirp Scaling 算法 (简称 CS 算法&#xff0c;即 CSA) 避免了 RCMC 中的插值操作。该算法基于 Scaling 原理&#xff0c;通过对 chirp 信号进行频率调制&#xff0c;实现了对信号的尺度变换或平移。基于这种原理&#xff0c;可以通过相位相乘代替时域插值…

ssh连接docker容器处理备忘

1、查看容器ip&#xff0c;记下来之后要用 docker inspect elastic | grep IPAddress 2、使用root进入docker容器 docker exec -it -u root elastic /bin/bash 3、安装openssh #更新apt apt-get update#安装ssh client apt-get install openssh-client#安装ssh server apt-…

子类拷贝构造函数会调用父类拷贝构造函数吗?

一. 编译器提供的默认子类拷贝构造函数会调用父类拷贝构造函数。 #include <iostream> #include <string> using namespace std;class Parent { public:Parent(string home_address "中国") : m_home_address(home_address) {cout << "调用…

【网络安全】用永恒之蓝(Eternal blue)测试windows系统的安全性

一、kali默认账户和密码都为kali 攻击机&#xff1a;Linux 的 kali 目标机&#xff1a;Windows7 x64 二、kali、metasploit、metasploit 攻击 windows操作系统、metasploit 攻击 永恒之蓝 全流程 ①kali&#xff1a;是黑客攻击机。开源免费的Linux操作系统&#xff0c;含有300…

11.30_黑马Redis实战篇分布式锁

实战篇9 设立一个在jvm外的锁监视器&#xff0c;可以处理多线程的问题 实战篇10 获取锁的时候&#xff0c;要同时发生获取锁以及设置到期时间。 实战篇11 thinking&#xff1a;JAVA中的自动拆箱与装箱&#xff1f; 【Java基础】自动拆装箱_Elephant_King的博客-CSDN博客 TR…

【微服务 SpringCloudAlibaba】实用篇 · Feign服务远程调用

微服务&#xff08;7&#xff09; 文章目录 微服务&#xff08;7&#xff09;1. Feign替代RestTemplate1&#xff09;引入依赖2&#xff09;添加注解3&#xff09;编写Feign的客户端4&#xff09;测试5&#xff09;总结 2.自定义配置2.1 配置文件方式2.2 Java代码方式 3. Feign…

Unity随笔1 - 安卓打包JDK not found

今天遇到一个很奇怪的事情&#xff0c;之前可以正常打安卓包&#xff0c;但是突然报错如下&#xff1a; 提示很明显&#xff0c;找不到JDK了。可是我在下载Unity的时候明明安装了所有需要的组件&#xff0c;为什么今天突然不行。 看了眼Unity hub里面&#xff0c;没问题。 那就…

go elasticsearch 测试实例

// 查询列表数据 func QueryOperateList(ctx context.Context, esClient *elastic.Client, index string, pageNum, pageSize int, start, end int64, execSql string, list []interface{}, operateAccount string, operateAddr string, maxRows, minRows int, dbAddr, namespa…

【UGUI】实现背包的常用操作

1. 添加物品 首先&#xff0c;你需要一个包含物品信息的类&#xff0c;比如 InventoryItem&#xff1a; using UnityEngine;[CreateAssetMenu(fileName "NewInventoryItem", menuName "Inventory/Item")] public class InventoryItem : ScriptableObje…

【Azure 架构师学习笔记】- Azure Databricks (1) - 环境搭建

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 前言 Databricks 已经成为了数据科学的必备工具&#xff0c;今时今日你已经很难抛开它来谈大数据&#xff0c;它常用于做复杂的ETL中的T&#xff0c; 数据分析&#xff0c;数据挖掘等&#xff0c;…

[架构之路-255]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 架构设计 - 软件架构风格

目录 前言&#xff1a; 一、建筑风格 1.1 什么是建筑风格 1.2 常见的建筑风格 1.3 如何区分不同的建筑风格 二、软件架构风格概述 2.1 什么是软件架构风格 2.2 如何区分不同的软件架构风格 2.3 软件架构风格的发展阶段 2.4 软件架构风格与软件架构的区别 2.5 常见的…

在 S/4HANA、ECC 和 ERP 上轻松扩展或简化 SAP WM,并将其自动化到移动环境中

为您的 SAP WM 提供完整的本地 SAP 图形用户界面 基于原生通道架构&#xff08;NCA&#xff09;&#xff0c;iOS、Android 和手持 Scanguns 版 Liquid UI 可与 SAP WM 原生连接&#xff0c;同时保留 SAP GUI 丰富的事务处理功能。它使您无需编程即可直接从移动设备访问 MIGO、…

知识图谱最简单的demo实现——基于pyvis

1、前言 我们在上篇文章中介绍了知识图谱的简单实现&#xff0c;最后使用neo4j进行了展示&#xff0c;对于有些情况我们可能并不想为了查看知识图的结果再去安装一个软件去实现&#xff0c;那么我们能不能直接将三元组画出来呢/ 接下来我们就介绍一个可视化的工具pyvis&#…

Memcached最新2023年面试题,高级面试题及附答案解析

文章目录 01、Memcached是什么&#xff0c;有什么作用&#xff1f;02、Memcached的多线程是什么&#xff1f;如何使用它们&#xff1f;03、Memcached与Redis的区别&#xff1f;04、如果缓存数据在导出导入之间过期了&#xff0c;怎么处理这些数据呢&#xff1f;05、如何实现集群…

网站提示不安全?

随着互联网的普及和发展&#xff0c;网络安全问题日益严重。黑客攻击、数据泄露、恶意软件等问题层出不穷&#xff0c;给企业和个人带来了巨大的损失。在这个背景下&#xff0c;确保网站安全显得尤为重要&#xff0c;而使用SSL证书是解决这些问题的有效措施。 什么是SSL证书&am…