彻底理解前端模块化

目录

  • 引入
    • 历史
    • 问题
  • CommonJS
    • exports导出
    • module.exports导出
    • require导入
    • 加载过程
    • 缺点
  • AMD规范(基本不用)
    • `require.js`使⽤
  • CMD规范(基本不用)
    • SeaJS的使⽤
  • ES Module
    • 简单使用
    • export关键字
    • import关键字
    • export和import结合
    • default⽤法
    • import函数
    • import meta
    • ES Module的解析

模块化是一种处理复杂系统分解成为更好的可管理模块的方式,模块化开发最终的目的是将程序划分成一个个小的结构

  • 这个结构中编写属于自己的逻辑代码,有自己的作用域,定义变量名词时不会影响到其他的结构
  • 可以将自己希望暴露的变量、函数、对象等导出给其结构使用
  • 可以通过某种方式,导入另外结构中的变量、函数、对象等

引入

历史

  • 在网页开发的早期,Brendan Eich开发JavaScript仅仅作为一种脚本语言,做一些简单的表单验证或动画实现等,那个时候代码还是很少的,只需要将JavaScript代码写到<script>标签即可,没有必要放到多个文件中来编写

  • 随着前端和JavaScript的快速发展,JavaScript代码变得越来越复杂了

    • ajax的出现,前后端开发分离,意味着后端返回数据后,我们需要通过JavaScript进行前端页面的渲染

    • SPA的出现,前端页面变得更加复杂:包括前端路由、状态管理等等一系列复杂的需求需要通过JavaScript来实现

    • 包括Node的实现,JavaScript编写复杂的后端程序,没有模块化是致命的硬伤

  • 所以,模块化已经是JavaScript一个非常迫切的需求:

    • 但是JavaScript本身,直到ES6(2015)才推出了自己的模块化方案

    • 在此之前,为了让JavaScript支持模块化,社区出了很多不同的模块化规范:AMD、CMD、CommonJS

问题

早期没有模块化带来了很多的问题:比如命名冲突的问题,我们是使用 立即函数调用表达式(IIFE 来解决的,但也会有其他问题:

  • 必须记得每一个模块中返回对象的命名,才能在其他模块使用过程中正确的使用

  • 代码写起来混乱不堪,每个文件中的代码都需要包裹在一个匿名函数中来编写

  • 在没有合适的规范情况下,每个人都可能会任意命名、甚至出现模块名称相同的情况

需要制定一定的规范来约束每个人都按照这个规范去编写模块化的代码,JavaScript社区为了解决上面的问题,涌现出一系列好用的规范,接下来我们一一学习

CommonJS

CommonJS 是一种模块系统规范,主要用于在服务器端环境(如 Node.js)中管理模块。它提供了模块的定义、加载、导出机制,允许开发者在不同模块之间共享代码。Node.js 中,CommonJS 是默认的模块系统,虽然现在 Node.js 也支持 ECMAScript 模块,但 CommonJS 仍然广泛使用

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

  • NodeCommonJS在服务器端一个具有代表性的实现,Node中对CommonJS进行了支持和实现

  • Browserify库是CommonJS在浏览器中的一种实现

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

  • Node中每一个js文件都是一个单独的模块

  • 这个模块中包括CommonJS规范的核心变量:exports、module.exports、require,可以使用这些变量来方便的进行模块化开发

    • exportsmodule.exports可以负责对模块中的内容进行导出

    • require函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容

exports导出

exports是一个对象,我们可以在这个对象中添加很多个属性,添加的属性会导出

// a.js
function add(num1, num2) {return num1 + num2;
}
const message = "hello world";
console.log(exports); // {}
exports.add = add;
exports.message = message;// main.js
// const { add, message } = require("./a"); // 可以拿到文件中导出的exports对象,相当于引用赋值
// console.log(add(10, 30)); // 40
// console.log(message); // hello worldconst a = require("./a");
console.log(a.add(10, 30)); // 40
console.log(a.message); // hello world

上面代码原理:
在这里插入图片描述

exports是一个对象,在内存中就会有个对象地址比如是0x100,那么exports就指向这个引用地址

当执行const a = require("./a")require就会找到a模块导出的exports,把exports的引用地址赋值给aaexports指向了同一个对象

也就意味着你在main.js两秒后修改了message的值,两秒后在a.js中获取时会变成你新改的值

module.exports导出

// b.js
function add(num1, num2) {return num1 + num2;
}
const message = "hello world";// 方式一
// module.exports.add = add;
// module.exports.message = message;
// console.log(module.exports === exports); // true// 方式二:开发中常用,module.exports赋值新对象更灵活方便
module.exports = {add,message,
};// main.js
const b = require("./b");
console.log(b.add(10, 20)); // 30
console.log(b.message); // hello world

上面代码原理:

在这里插入图片描述

module.exportsexports有什么关系呢?

  • exportsmodule.exports 的简写,起初它们都指向同一个对象的引用地址

  • module.exports = exports = main.js中引入的变量

我们开发中常用的是module.exports,而且他俩还相等,那有exports还有什么意义那?

  • CommonJS中是没有module.exports的概念的,但Node要实现commonjs标准所以有exports,并且让exports = module.exports

  • 但为了实现模块的导出,Node中使用的是Module的类,每⼀个模块都是Module的⼀个实例也就是module

  • 所以Node中真正⽤于导出的其实不是exports,使用require导入时查找的本质也不是exports,而是module.exports

  • 也就是说module.exports可以通过赋值为一个新对象导出,但exports不行,因为改变了exports的引用没有用,node中找的还是module.exports

require导入

我们已经知道,require是⼀个函数,可以帮助我们引⼊⼀个⽂件(模块)中导出的对象

require的查找规则是怎么样的呢?导⼊格式如下:require(X)

  • X是⼀个Node核⼼内置模块,⽐如path、http:直接返回核⼼模块,并且停⽌查找

    console.log("path:", require("path"));
    console.log("http:", require("http"));
    

    在这里插入图片描述

  • X是以 ./..//(根⽬录)开头的

    • 第⼀步:将X当做⼀个⽂件在对应的⽬录下查找

      1. 直接查找⽂件X

      2. 查找X.js⽂件

      3. 查找X.json⽂件

      4. 查找X.node⽂件

    • 第⼆步:没有找到对应的⽂件,将X作为⼀个⽬录:查找⽬录下⾯的index⽂件

      1. 查找X/index.js⽂件

      2. 查找X/index.json⽂件

      3. 查找X/index.node⽂件

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

    在这里插入图片描述

  • 直接是⼀个X(没有路径),并且X不是⼀个核⼼模块

    • 我们可以看到它是会报错的
      在这里插入图片描述

    • 引入的hello我们可以在目录下建个node_modules里面再建个hello文件夹并包含index.js入口文件,这时require就可以找到了,这也是npm install 依赖 下载依赖的原理,那么axios我们就可以用npn install 下载
      在这里插入图片描述

    • 那么它的查找规律就是会先在当前目录的node_modules文件夹(必须有入口文件)中寻找

    • 没有找到的话,会再到上一级目录的node_modules文件夹中寻找,直到找到根目录还没有就会报错

加载过程

  • 模块在被第一次引入时,模块中的js代码会被运行一次,这个我们在上面的演习中就能发现

  • 模块被多次引入时,会缓存,最终只加载(运行)一次

    • 这是因为每个模块对象module都有一个属性loaded记录是否被加载过,默认为false
  • 如果有循环引入,那么加载顺序是什么?

    • 这个其实是一种数据结构:图结构

    • 图结构在遍历的过程中,有深度优先搜索DFS, depth first search)和广度优先搜索BFS, breadth first search

    • Node采用的是深度优先算法(在一层里面走到底)main -> aaa -> ccc -> ddd -> eee ->bbb
      在这里插入图片描述

缺点

  • CommonJS加载模块是同步的

    • 意味着只有等到对应的模块加载完毕,当前模块中的内容才能被运⾏

    • 在服务器不会有什么问题,因为服务器加载的js⽂件都是本地⽂件,加载速度⾮常快

  • 如果将它⽤于浏览器呢?

    • 浏览器加载js⽂件需要先从服务器将⽂件下载下来,之后再加载运⾏

    • 那么采⽤同步的就意味着后续的js代码都⽆法正常运⾏,即使是⼀些简单的DOM操作

    • 在浏览器中,我们通常不使⽤CommonJS规范,在webpack中使⽤CommonJS是另外⼀回事

  • 在早期为了可以在浏览器中使⽤模块化,通常会采⽤AMDCMD

    • ⽬前⼀⽅⾯现代的浏览器已经支持ES Modules

    • 另⼀⽅⾯借助于webpack等⼯具可以实现对CommonJS或者ES Module代码的转换

    • AMDCMD已经使⽤⾮常少了

AMD规范(基本不用)

AMD主要是⽤于浏览器的⼀种模块化规范

  • AMD是Asynchronous Module Definition`(异步模块定义)的缩写,⽤的是异步加载模块

  • 事实上 AMD的规范还要早于CommonJS,但是CommonJS⽬前依然在被使⽤,⽽AMD使⽤的较少了

  • 规范只是定义代码的应该如何去编写,需有了具体的实现才能被应⽤,AMD实现的⽐较常⽤的库是require.jscurl.js

require.js使⽤

  • 下载require.js:下载地址:https://github.com/requirejs/requirejs 找到其中的require.js⽂件

  • 定义HTMLscript标签引⼊require.js和定义⼊⼝⽂件:

    • <script src="./lib/require.js" data-main="./index.js"></script>

    • data-main属性的作⽤是在加载完src的⽂件后会加载执⾏该⽂件

CMD规范(基本不用)

CMD规范也是⽤于浏览器的⼀种模块化规范:

  • CMDCommon Module Definition(通⽤模块定义)的缩写

  • ⽤的也是异步加载模块,但是它将CommonJS的优点吸收了过来,但是⽬前CMD使⽤也⾮常少了

  • CMD也有⾃⼰⽐较优秀的实现⽅案:SeaJS

SeaJS的使⽤

  • 下载SeaJS:下载地址:https://github.com/seajs/seajs 找到dist⽂件夹下的sea.js

  • 引⼊sea.js和使⽤主⼊⼝⽂件seajs是指定主⼊⼝⽂件的

ES Module

JavaScript没有模块化⼀直是它的痛点,所以才会产⽣我们前⾯学习的社区规范:CommonJS、AMD、CMD等,所以在 ECMA 推出⾃⼰的模块化系统时,⼤家也是很兴奋

  • ES Module模块采用 export负责将模块内的内容导出import负责从其他模块导入内容来实现模块化

  • ES Module模块允许编译器在编译时进行静态分析,也加入了动态引用的方式

  • 使用ES Module将自动采用严格模式:use strict

简单使用

  • 在浏览器中,ES Modules 通过 <script type="module"> 标签引入,来声明这个脚本是一个模块

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script src="./main.js" type="module"></script></body>
    </html>
    

    在这里插入图片描述

    但浏览器打开本地文件会报错,这个在MDN上面有给出解释:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules#其他模块与标准脚本的不同

    需要注意本地测试:如果你通过本地加载 HTML 文件(比如一个 file:// 路径的文件),你将会遇到 CORS 错误,因为 JavaScript 模块安全性需要。你需要通过一个服务器来测试

    这里使用的VSCode插件:Live Server,可以执行并打印main.js代码

  • Node.js 中使用 ES Modules(ESM)可以通过以下几种方式实现:

    • 如果你的模块文件使用 .mjs 扩展名,Node.js 会将其识别为 ES Module
    // example.mjs
    export const greeting = "Hello, World!";
    export function sayHello() {console.log(greeting);
    }// main.mjs
    import { sayHello } from './example.mjs';
    sayHello(); // 输出: Hello, World!
    
    • 如果你希望在整个项目中使用 ES Modules,而不仅仅是单个文件,可以在 package.json 文件中添加 "type": "module",所有 .js 文件都将被视为 ES Modules
    // package.json
    {"name": "my-project","version": "1.0.0","type": "module"
    }// example.js
    export const greeting = "Hello, World!";
    export function sayHello() {console.log(greeting);
    }// main.js
    import { sayHello } from './example.js';
    sayHello(); // 输出: Hello, World!
    

export关键字

export关键字将一个模块中的变量、函数、类等导出

  • 方式一:想导出谁就在语句声明的前面直接加上export关键字

  • 方式二:想导出谁则将需要导出的标识符,放到export后面的 {}

    • 注意:这里的 {} 里面不是ES6的对象字面量的增强写法,{} 也不是表示一个对象export { message: message } 是错误的写法;
  • 方式三:在方式二导出时给标识符起一个别名

// 方式一
export const message1 = "hello world1";
export function add1(num1, num2) {return num1 + num2;
}
export class Person1 {constructor(name) {this.name = name;}
}// 方式二
const message2 = "hello world2";
function add2(num1, num2) {return num1 + num2;
}
class Person2 {constructor(name) {this.name = name;}
}
export { message2, add2, Person2 };// 方式三
const message3 = "hello world3";
function add3(num1, num2) {return num1 + num2;
}
class Person3 {constructor(name) {this.name = name;}
}
export { message3, add3 as add0, Person3 as Person0 };

import关键字

import关键字负责从另外一个模块中导入内容

  • 方式一:import { 标识符列表 } from '模块'

    • 注意:这里的 {} 也不是一个对象,里面只是存放导入的标识符列表内容
  • 方式二:通过as关键字在导入时给标识符起别名

  • 方式三:通过 * as 自己名字 将模块功能放到一个模块功能对象上

// 结合export中的代码学习
import {message1, // 方式一message2,message3,add0 as add3, // 方式二add1,add2,Person0 as Person3,Person1,Person2,
} from "./a.js";import * as a from "./a.js"; // 方式三console.log(message1,message2,message3,add1,add2,add3,Person1,Person2,Person3,a.message1,a.message2,a.message3,a.add1,a.add2,a.add0,a.Person1,a.Person2,a.Person0
);

export和import结合

在开发和封装一个功能库时,通常希望将暴露的所有接口放到一个文件中,这样方便指定统一的接口规范也方便阅读,这个时候就可以使用exportimport结合使用

/* util/index 通常是不编写逻辑的,在这里统一导入并导出 */// 方式一
import {message1,message2,message3,add0 as add3,add1,add2,Person0 as Person3,Person1,Person2,
} from "./a.js";
import { getData } from "./b.js";export {message1,message2,message3,add3,add1,add2,Person3,Person1,Person2,getData,
};// 方式二:结合
export {message1,message2,message3,add0 as add3,add1,add2,Person0 as Person3,Person1,Person2,
} from "./a.js";
export { getData } from "./b.js";// 方式三:建议当有相应的文档时再这样写
export * from "./a.js";
export * from "./b.js";

default⽤法

前面学习的导出都是有名字的导出(named exports):在导出export时指定了名字,在导入import时需要知道具体的名字,文件只有一个想要导出的内容并且文件名已经概括时就可以使用默认导出(default export

  • 默认导出:在一个模块中,只能有一个默认导出

    • 默认导出export时可以不指定名字

    • 在导入时不需要使用 {},并且可以自己来指定名字

    • 也方便我们和现有的CommonJS等规范相互操作

    /* validMobile.js */
    // 方式一
    // function validMobile(str) {
    //   const reg = /^1[3-9]\d{9}$/;
    //   return reg.test(str);
    // }
    // export default validMobile;// 方式二
    export default (str) => {const reg = /^1[3-9]\d{9}$/;return reg.test(str);
    };/* main.js */
    import validMobile from "./validMobile.js";
    console.log(validMobile("12345678910")); // false
    

import函数

import静态的,这意味着在编译或打包阶段,模块依赖关系就已经确定了JavaScript 引擎需要在脚本开始执行之前分析所有的模块和依赖项,以便优化打包、代码分割、死代码消除等操作。如果需要根据不同的条件,动态来选择加载模块,这个时候我们需要使⽤ import() 函数

  • import()是异步的,返回的是个promise

  • 结合 export default 使用时,要用.default取值

/* a.js */
export function add(num1, num2) {return num1 + num2;
}/* validMobile.js */
export default (str) => {const reg = /^1[3-9]\d{9}$/;return reg.test(str);
};/* main.js */
import validMobile from "./validMobile.js";
console.log(validMobile("12345678910")); // false
if (validMobile("13626068779")) {// 结合 exportimport("./a.js").then((a) => {console.log(a.add(10, 20)); // 30});
} else {// 结合 export defaultimport("./validMobile.js").then((v) => {console.log(v.default("13626068779")); // true});
}

import meta

import.meta是⼀个给JavaScript模块暴露特定上下⽂的元数据属性的对象,它包含了这个模块的信息,⽐如说这个模块的URL

在这里插入图片描述

  • url模块的完整 URL,包括查询参数和/或哈希(位于?或之后#)。在浏览器中,这是获取脚本的 URL(对于外部脚本)或包含文档的 URL(对于内联脚本)。在 Node.js 中,这是文件路径(包括file://协议)

  • resolve:使用当前模块的 URL 作为基础,将模块说明符解析为 URL

ES Module的解析

ES Module是如何被浏览器解析并且让模块之间可以相互引⽤的呢?

  • 可以看下这篇文章:https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/

  • ES Module的解析过程可以划分为三个阶段

    • 阶段⼀:构建(Construction),根据地址查找js⽂件,并且下载,将其解析成模块记录(Module Record

      1. 当浏览器(或 JavaScript 引擎)遇到 <script type="module">import 语句时,它会识别这是一个 ESM 模块

      2. 解析器会识别所有的 import 语句,并在构建依赖图的同时请求这些模块文件的下载

      3. 依赖图构建的过程中,浏览器会为每个模块分配一个唯一的模块记录,这个模块记录保留了模块的状态和依赖关系

      4. 模块环境记录可参考学习这篇文章:https://blog.csdn.net/qq_45730399/article/details/141196562?spm=1001.2014.3001.5501

    在这里插入图片描述

    • 阶段⼆:实例化(Instantiation),对模块记录进⾏实例化,并且分配内存空间,解析模块的导⼊和导出语句,把模块指向对应的内存地址

      1. 在所有依赖项(模块)都下载完成后,浏览器会执行模块链接。在此阶段模块的依赖关系会被处理,导入的模块和导出的符号都会被绑定起来

      2. 在这个过程中,浏览器不会执行模块的代码,只是检查模块之间的依赖关系,并将导入和导出的值关联起来

    • 阶段三:运⾏(Evaluation),运⾏代码,计算值,并且将值填充到内存地址中

      1. 关联完成后才会开始逐个执行模块的代码,模块执行后,模块的状态会更新,表明它已经执行完毕,之后如果再次请求该模块,执行的结果会直接从缓存中获取

    在这里插入图片描述

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

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

相关文章

YOLOv10改进 | 特征融合篇,YOLOv10添加iAFF(多尺度通道注意力模块),二次创新C2f结构,提升小目标检测能力

摘要 特征融合,即来自不同层或分支的特征的组合,是现代网络架构中无处不在的一部分。虽然它通常通过简单的操作(如求和或拼接)来实现,但这种方式可能并不是最佳选择。在这项工作中,提出了一种统一且通用的方案,即注意力特征融合(Attentional Feature Fusion),适用于…

RK3568笔记六十三:基于LVGL的Linux相机

若该文为原创文章,转载请注明原文出处。 记录移植韦老师的基于LVGL的Linux相机项目,主要是想学习如何在LVGL下显示摄像头数据。 此项目是基于老师的源码框架移植的,地址是lv_100ask_linux_camera: 基于LVGL的Linux相机 (gitee.com) 个人使用的是RK3568,正点原子板子,所以…

WordPress 要求插件开发人员进行双因素身份验证

全球超过40%的网站由 WordPress 提供支持&#xff0c;其庞大的插件和主题生态系统在全球范围内提供了灵活性和定制性。然而&#xff0c;这种受欢迎程度也使其成为网络攻击的主要目标。 WordPress 将为所有插件和主题开发人员引入强制性双因素身份验证 (2FA)&#xff0c;以应对…

《经典图论算法》约翰逊算法(Johnson)

摘要&#xff1a; 1&#xff0c;约翰逊算法的介绍 2&#xff0c;约翰逊算法的实现步骤 3&#xff0c;约翰逊算法的准确性验证 4&#xff0c;约翰逊算法的代码实现 1&#xff0c;约翰逊算法的介绍 约翰逊算法(Johnson algorithm)是在稀疏图上求每对顶点之间最短路径的一种算法&a…

《解锁高效流程设计:深度剖析责任链模式与实战应用》

《解锁高效流程设计&#xff1a;深度剖析责任链模式与实战应用》 责任链模式 是一种行为设计模式&#xff0c;它允许多个对象来处理请求&#xff0c;而不预先指定具体的处理者。多个处理对象被连接成一条链&#xff0c;沿着这条链传递请求&#xff0c;直到某个处理对象决定处理…

SOMEIP_ETS_130: SD_Multicast_FindService_with_unicast_Flag_to_0

测试目的&#xff1a; 验证DUT能够忽略带有设置为0的单播标志的多播FindService请求&#xff0c;并以单播OfferService消息作为响应。 描述 本测试用例旨在确保DUT在接收到一个设置了单播标志为0的多播FindService请求时&#xff0c;能够忽略该标志并按照SOME/IP协议的要求&…

旧衣回收小程序搭建,开发功能优势

随着人们生活水平、消费水平的提高&#xff0c;在日常生活中产生了大量的限制物品&#xff0c;为了减少浪费&#xff0c;越来越多的人开始重视环保回收。旧衣物作为一种新型的回收方式&#xff0c;也逐渐得到了大众的关注&#xff0c;旧衣物回收市场发展规模也在持续上升&#…

【C++】STL详解之string类

目录 什么是STL STL的版本 STL的六大组件 STL的缺陷 一.string的定义方式 二. string的插入 1.使用push_back进行尾插 2.使用insert插入 三.string的拼接 四.string的删除 1.使用pop_back进行尾删 2.使用erase进行删除 五.string的查找 1.使用find正向搜索第一个…

快速排序(plus)与单调栈道,力扣912.排序数组​​​​​​​力扣215.数组中的第k大个元素力扣17.14最小的k个数单调栈力扣.柱状图中最大的矩形

目录 力扣912.排序数组​​​​​​​ 力扣215.数组中的第k大个元素 力扣17.14最小的k个数 单调栈 力扣.柱状图中最大的矩形 力扣912.排序数组 快速排序:最重要的就是数据划分&#xff0c;叫做partation left往后走&#xff0c;假如遇到比key小的&#xff0c;left是因为&a…

解释器模式原理剖析和Spring中的应用

解释器模式原理剖析和Spring中的应用 解释器模式 是一种行为型设计模式&#xff0c;它定义了一种语言的文法表示&#xff0c;并提供了一个解释器来处理该文法的表达式。解释器模式可以用于构建语法解释器&#xff0c;例如计算器、简单编程语言的解释器等。 核心思想&#xff1a…

My_String完善

#include "my_string_ok.h" My_string_Ok::My_string_Ok():size(20) { len 0; ptr new char[size]; ptr[len] \0; } My_string_Ok::My_string_Ok(int num,char c) { cout<<"有参构造"<<endl; ptr new char [20] ; len 0; for…

深度学习技术在超材料科学中的应用与实操

人工智能算法赋能材料设计与应用专题培训 前沿背景 人工智能与材料科学的融合趋势&#xff1a;在材料科学领域&#xff0c;人工智能&#xff08;AI&#xff09;的引入正在引发一场革命。传统的材料设计和优化依赖于经验和试错方法&#xff0c;这不仅耗时且成本高昂。关于AI赋…

安科瑞Acrel-1000DP分布式光伏监控系统在鄂尔多斯市鄂托克旗巴音乌苏六保煤矿5MW分布式光伏项目中的应用

安科瑞 华楠 摘 要&#xff1a;分布式光伏发电就是将太阳能光伏板分散布置在各个区域&#xff0c;通过小规模、模块化的方式实现电能的并网或独立使用&#xff0c;这种发电方式具有就近发电、就近并网、就近转换、就近使用的特点。近年来&#xff0c;技术进步和政策支持推动了光…

Python批量合并365个工作表的2种方法

一、引言 小明刚进入到新公司&#xff0c;就被委以重任&#xff1a;将365个Excel文件中的英文表头修改为中文。传统方法是逐一打开每个文件&#xff0c;手动修改标题&#xff0c;然后保存&#xff0c;最后再合并。这种方法不仅耗时耗力&#xff0c;还容易出错。如果用Python就…

下水道内缺陷识别检测数据集 yolo数据集 共2300张

下水道内缺陷识别检测数据集 yolo数据集 共2300张 下水道内部缺陷识别数据集&#xff08;Sewer Interior Defect Recognition Dataset, SIDRD&#xff09; 摘要 SIDRD 是一个专门针对下水道内部缺陷识别的数据集&#xff0c;旨在为城市基础设施维护和管理提供一个标准化的训练…

Qt:关于16进制数转化那些事

前言 由于当时做UDP通信的时候使用16进制数与QString的相互转换&#xff0c;但是当时我所要求的转换不仅仅是转化过去就行了&#xff0c;我还有字节数要求&#xff0c;就是这个16进制数占据多少位那么转化后的数据就该占据多大的空间。 正文 1 将 QString 转换为16进制字符串…

【Redis入门到精通五】Java如何像使用MySQL一样使用Redis(jedis安装及使用)

目录 Jedis 1.jedis是什么 2.jedis的安装配置 3.jedis的基础命令操作展示 1.set和get操作&#xff1a; 2.exists和del操作&#xff1a; 3.keys和type操作&#xff1a; 4. expire和ttl&#xff1a; Jedis Java 操作 redis 的客⼾端有很多&#xff0c;其中最知名的是 jedi…

STM32基础学习笔记-Timer定时器面试基础题5

第五章、TIMER 常见问题 1、基本概念&#xff1a;什么是定时器 &#xff1f;作用 &#xff1f;分类 &#xff1f; 2、时基单元 &#xff1f;组成 &#xff1f;计数模式 &#xff1f;溢出条件 &#xff1f; 溢出时间计算 &#xff1f; 3、systick原理 &#xff1f;代码讲解 &…

中国蚁剑(antSword)安装使用

antSword下载 antSword-Loader下载 作者&#xff1a;程序那点事儿 日期&#xff1a;2024/09/12 19:35 中国蚁剑&#xff08;AntSword&#xff09;是一款跨平台的开源网站管理工具&#xff0c;旨在满足渗透测试人员的需求。它是一个功能强大的工具&#xff0c;可以帮助用户管理…

基于CPS CPSQ5453CPSQ5352的易冲车灯方案

一、方案描述 CPS易冲&#xff08;CONVENIENTPOWER&#xff09;针对汽车矩阵大灯&#xff0c;推出 基于CPS CPSQ5453 & CPSQ5352的汽车矩阵式大灯方案。 开发板搭载的主要器件有CPS的独立双通道恒压恒流升压控制器&#xff1a;CPSQ5453、独立双通道LED恒流降压变换器&#…