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

useEffect

useEffect

    • 1.依赖项是什么?
    • 2.useEffect怎么知道依赖项数组发生了改变?
    • 3.依赖项的改变会导致无限渲染吗?
    • 4.使用 Object.is 来比较新/旧 state 是否相等,浅比较?
    • 5.为什么要用浅比较,而不用深比较呢?
    • 6.如何在 useState 中处理副作用(例如,当状态更新时触发某个操作)?
    • 7.如何理解副作用Effect?
    • 8.如何理解纯渲染?
    • 9.useEffect何时执行?
    • 10.为什么在 useEffect 的依赖项数组中包含函数或对象可能导致问题?如何解决这个问题?
    • 11.如何在 useEffect 中模拟 componentDidMount 和 componentDidUpdate、componentWillUnmount 生命周期方法?
    • 12.当一个组件有多个 useEffect 时,它们的执行顺序是什么?
    • 13.如何使用 useEffect 实现一个定时器,并在组件卸载时清除它?
    • 14.为什么不能在 useEffect 回调函数中直接使用 async/await

1.依赖项是什么?

依赖项通常是指在 React Hooks 中用到的一个概念,尤其是在 useEffectuseMemouseCallback 等 Hooks 中。依赖项是一个数组用于列出在组件中使用的状态或属性这些状态或属性可能会影响到 Hook 的执行。当这些依赖项中的任何一个值发生变化时,Hook 就会重新执行

例如,在 useEffect 中,我们可以设置一个依赖项数组:

useEffect(() => {// 这里是副作用代码,当 `count` 发生变化时会重新执行console.log(`Count has changed to: ${count}`);// 一些可能的清理工作return () => {console.log('Cleanup code');};
}, [count]); // 这里是依赖项数组,包含了 count 变量

上面的代码中,useEffect Hook 有一个依赖项数组 [count]。当 count 值发生变化时,useEffect 会重新执行。如果不提供依赖项数组或将其设置为空数组([]),那么副作用函数只会在组件挂载时执行一次,并在组件卸载时执行清理操作。

依赖项的作用是确保 Hook 只在相关状态或属性发生变化时执行,而不是每次组件重新渲染时都执行。这有助于优化性能,避免不必要的操作。

2.useEffect怎么知道依赖项数组发生了改变?

useEffect 在内部使用了浅比较(shallow comparison)来检测依赖项数组是否发生了变化。当组件重新渲染时,useEffect当前渲染周期的依赖项数组上一次渲染周期的依赖项数组进行比较。如果其中任何一个元素发生了变化(即,它们的引用不相等),那么 useEffect 会认为依赖项数组发生了改变,并执行副作用函数。

举个例子,假设我们有以下代码:

const [count, setCount] = useState(0);useEffect(() => {console.log(`Count has changed to: ${count}`);
}, [count]);

在这个例子中,countuseEffect 的依赖项。当组件重新渲染时,React 会获取当前渲染周期的 count 值和上一次渲染周期的 count 值。如果它们不相等,那么 useEffect 会执行副作用函数。这里的比较是浅比较,也就是说,React 只检查 count 变量的引用是否相等,而不会深入比较它们的内部结构。

这种浅比较在大多数情况下是足够的,因为基本类型(如数字、字符串和布尔值)是不可变的而对象和数组通常会在更改时产生新的引用。然而,在某些情况下,浅比较可能会导致不必要的副作用执行,特别是当依赖项是可变对象或数组时。为避免这种情况,可以使用 useMemouseCallback 等其他 Hooks 来确保依赖项的引用在值实际发生变化时才会更改。

3.依赖项的改变会导致无限渲染吗?

依赖项的改变不会导致无限渲染,除非你在副作用函数内部引起了依赖项的改变。当依赖项改变时,useEffect 会执行副作用函数。如果副作用函数的执行结果是导致依赖项再次改变,那么会形成一个循环,从而导致无限渲染

举个例子:

const [count, setCount] = useState(0);useEffect(() => {// 这里的 setCount 会导致 count 值改变,从而触发 useEffect 再次执行setCount(count + 1);
}, [count]);

在这个例子中,useEffect 的副作用函数会调用 setCount 修改 count 的值。这会导致组件重新渲染,并再次执行 useEffect。由于 countuseEffect 的依赖项,每次 count 改变时,都会触发 useEffect,从而导致无限渲染。

为了避免无限渲染,你需要确保副作用函数不会在每次执行时都引起依赖项的改变。你可以通过在副作用函数内部添加条件判断或使用其他策略来实现这一点。例如,你可以这样修改上面的例子:

const [count, setCount] = useState(0);useEffect(() => {// 在条件满足时才更新 countif (count < 5) {setCount(count + 1);}
}, [count]);

最好不要在useEffect中改变依赖项,如果一定要改变,就要增加条件语句,避免死循环。

现在,useEffect 只会在 count 小于 5 时更新 count 的值。当 count 达到 5 时,副作用函数不再引起 count 的改变,从而避免了无限渲染。

4.使用 Object.is 来比较新/旧 state 是否相等,浅比较?

Object.is() 是一个 JavaScript 函数,用于比较两个值是否相等。这种比较被称为**“浅比较”(Shallow Comparison)**,它检查两个值是否具有相同的类型和值。Object.is() 的比较方式与 === 类似,但有两个关键区别:

  1. Object.is()NaN 视为与其自身相等(NaN 是 “Not a Number” 的缩写,表示一个非数字值)。
  2. Object.is()+0-0 视为不相等。

下面是一些示例:

Object.is(42, 42); // true
Object.is('hello', 'hello'); // true
Object.is(null, null); // true
Object.is(undefined, undefined); // true
Object.is(NaN, NaN); // true
Object.is(+0, -0); // false

在 React 的 Hooks 中,useStateuseReducer更新组件状态时使用 Object.is() 进行浅比较,以确定是否需要重新渲染组件。这意味着,只有当新的状态值与旧的状态值不相等时,组件才会重新渲染

请注意,浅比较并不会递归地比较对象的属性。因此,当使用对象作为状态时,如果对象内部的属性发生变化,但对象的引用仍然相同Object.is() 则认为这两个对象相等,导致组件不会重新渲染。在这种情况下,可以使用不可变数据结构(immutable data structures)或通过创建一个新对象来确保触发组件更新。

5.为什么要用浅比较,而不用深比较呢?

使用浅比较而不是深比较的原因主要有以下几点:

  1. 性能:深比较需要递归地遍历整个对象结构,可能涉及大量的计算。对于大型对象或嵌套结构较深的对象,这可能导致性能问题。而浅比较只需要比较对象的第一层属性,因此性能开销更小

  2. 简化:在大多数情况下,React 组件的状态更新很少涉及到深层嵌套的对象结构。浅比较足以满足大部分使用场景的需求,同时可以简化实现。

  3. 不可变性:在 React 中,一个推荐的做法是尽量使用不可变数据结构。当你更新状态时,而不是直接修改对象而是创建一个新对象。这样,浅比较就足够检测出状态是否发生了变化。

  4. **避免死循环:**深比较可能会导致死循环,尤其是在对象中存在循环引用的情况下。浅比较可以避免这种情况。

总之,浅比较在性能、简化和实用性方面都比深比较更有优势。对于那些需要深度比较的场景,开发者可以在组件内部自行实现,以满足特定需求。

6.如何在 useState 中处理副作用(例如,当状态更新时触发某个操作)?

可以使用 useEffect 来处理副作用。useEffect 会在组件挂载卸载以及依赖项更改时执行。如果需要在某个状态更新时执行副作用,可以将该状态作为 useEffect 的依赖项

import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);useEffect(() => {document.title = `Count: ${count}`;return () => {document.title = 'React App';};}, [count]);return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
}export default Example;

7.如何理解副作用Effect?

在 React 中,副作用(side effects)是指在组件的生命周期内发生的那些与纯渲染无关的行为。它们可能会影响组件之外的部分,包括但不限于:

  1. **数据获取:**从服务器或本地获取数据并在组件中显示。
  2. 订阅:订阅数据源以便在新数据可用时更新组件。
  3. DOM 操作:直接操作 DOM(例如,修改样式、属性或者添加事件监听器)。
  4. 定时器:使用 setTimeoutsetInterval 定时执行某些操作。

这些副作用通常会在组件挂载、卸载和更新时执行。在类组件中,我们需要使用生命周期方法(如 componentDidMountcomponentDidUpdatecomponentWillUnmount)来处理副作用。而在函数组件中,我们可以使用 useEffect Hook 来处理副作用。

8.如何理解纯渲染?

纯渲染(Pure Rendering)是指一个组件的渲染行为完全取决于其接收到的属性(props)和状态(state),即相同的输入总是产生相同的输出。纯渲染组件不会产生其他副作用,如修改全局变量、改变 DOM 之外的部分、触发网络请求等。

与纯渲染相对的是非纯渲染或有副作用的渲染。这些组件在渲染过程中可能产生与渲染无关的行为,如数据获取、订阅、DOM 操作等。这些副作用可能会影响到组件之外的部分,并且与组件的状态和属性有关

下面是两个组件的示例,一个是不纯的组件(非纯渲染组件),另一个是纯组件(纯渲染组件):

  1. 不纯的组件(有副作用):
import React, { useState, useEffect } from 'react';function NonPureComponent() {const [time, setTime] = useState(new Date().toLocaleTimeString());useEffect(() => {const timer = setInterval(() => {setTime(new Date().toLocaleTimeString());}, 1000);return () => {clearInterval(timer);};}, []);return (<div><h1>当前时间:{time}</h1></div>);
}

在这个不纯的组件中,我们使用 useEffect Hook 来创建一个定时器,用于每秒更新当前时间。该组件具有副作用,因为它创建了一个定时器,并在组件卸载时清除定时器。这些副作用会影响到组件之外的部分(例如全局的计时器)

  1. 纯组件(纯渲染):
import React from 'react';function PureComponent({ title, content }) {return (<div><h1>{title}</h1><p>{content}</p></div>);
}

在这个纯组件中,它仅仅根据接收到的 titlecontent 属性来渲染。相同的输入(属性)总是产生相同的输出(渲染结果)。这个组件没有任何副作用,完全取决于传入的属性。因此,这是一个纯渲染组件。

setCount(prevCount => prevCount + 1);

9.useEffect何时执行?

useEffect 的回调函数会在组件挂载后每次依赖项更新时执行。如果您提供了一个空的依赖项数组([]),则 useEffect 只会在组件挂载后执行一次。

当您在 useEffect 的回调函数中返回一个函数时,该函数将被作为清理函数。清理函数会在以下情况执行:

  1. 当组件卸载时。
  2. 当依赖项发生变化时,也就是说,在执行新的副作用之前,先执行清理函数以清除之前的副作用。

这是一个简单的示例:

import React, { useState, useEffect } from 'react';function MyComponent() {const [count, setCount] = useState(0);useEffect(() => {console.log('Component did mount or update.');return () => {console.log('Component will unmount or dependencies changed.');};}, [count]); // 依赖项数组return (<div><button onClick={() => setCount(count + 1)}>Increment</button></div>);
}

在这个例子中,当组件挂载后和每次 count 变化时,useEffect 的回调函数都会执行。相应地,当组件卸载依赖项 count 发生变化时,清理函数将被执行。

10.为什么在 useEffect 的依赖项数组中包含函数或对象可能导致问题?如何解决这个问题?

函数或对象作为依赖项的问题: 如果函数或对象在每次渲染时都被重新创建,它们的引用将改变,导致 useEffect 不断地重新执行。为了解决这个问题,可以使用 useCallback、useMemo 或将函数/对象移至组件外部。

11.如何在 useEffect 中模拟 componentDidMount 和 componentDidUpdate、componentWillUnmount 生命周期方法?

为了模拟 componentDidMount,将依赖项数组设置为空

为了模拟 componentDidUpdate,将需要观察的变量放入依赖项数组

在 useEffect 内返回一个清理函数,该函数将在组件卸载时执行。

12.当一个组件有多个 useEffect 时,它们的执行顺序是什么?

按照它们在代码中出现的顺序依次执行。

13.如何使用 useEffect 实现一个定时器,并在组件卸载时清除它?

useEffect(() => {const timer = setTimeout(() => {// 执行操作}, 1000);return () => {clearTimeout(timer);};
}, []);

14.为什么不能在 useEffect 回调函数中直接使用 async/await

useEffect 回调函数中直接使用 async/await 是不被允许的,原因如下:

  1. useEffect 的设计是用于处理副作用,它期望接收一个同步函数作为参数。当你将一个异步函数作为参数传递给 useEffect 时,这个异步函数会返回一个 Promise 对象,而不是一个清理函数。这会导致 React 抛出警告,因为它期望你返回一个可用于清理副作用的函数(或者不返回任何内容)。

  2. 直接在 useEffect 中使用 async/await 可能导致意外的行为。因为异步函数的执行是非阻塞性的,useEffect 可能在异步操作完成之前就被重新调用或清理,这可能会导致竞争条件和潜在的错误

为了正确地在 useEffect 中使用 async/await,你可以在 useEffect 内部定义一个异步函数并立即调用它。这样做的好处是,你可以在清理函数中处理异步操作(例如取消请求)以防止内存泄漏和竞争条件

下面是一个示例:

useEffect(() => {const fetchData = async () => {try {const data = await fetch(/* ... */);// 处理数据} catch (error) {// 处理错误}};fetchData();
}, []);

这种方法允许你在 useEffect 中正确处理异步操作,同时遵循 React 的要求。

相关文章:

useEffect

useEffect 1.依赖项是什么&#xff1f;2.useEffect怎么知道依赖项数组发生了改变&#xff1f;3.依赖项的改变会导致无限渲染吗&#xff1f;4.使用 Object.is 来比较新/旧 state 是否相等&#xff0c;浅比较&#xff1f;5.为什么要用浅比较&#xff0c;而不用深比较呢&#xff1…...

如何利用splice()和slice()方法操作数组

如何利用splice&#xff08;&#xff09;和slice&#xff08;&#xff09;方法操作数组 前言splice()是什么&#xff0c;有什么用&#xff1f;怎么用&#xff1f;slice()是什么&#xff0c;有什么用&#xff1f;怎么用&#xff1f;splice和slice方法的区别小结 前言 splice&am…...

一文读懂ChatGPT(全文由ChatGPT撰写)

最近ChatGPT爆火&#xff0c;相信大家或多或少都听说过ChatGPT。到底ChatGPT是什么&#xff1f;有什么优缺点呢&#xff1f; 今天就由ChatGPT自己来给大家答疑解惑~ 全文文案来自ChatGPT&#xff01; 01 ChatGPT是什么 ChatGPT是一种基于人工智能技术的自然语言处理系统&…...

如何提升应届生职场竞争力

引言 对于应届毕业生来说&#xff0c;进入职场是既令人兴奋又具有挑战性的。面对竞争激烈的就业市场&#xff0c;提高自身的职场竞争力对于应届生来说尤为重要。本文旨在为应届生提供有价值的见解和实用的策略&#xff0c;帮助他们提升职场竞争力&#xff0c;增加在就业市场中的…...

David Silver Lecture 5: Model-Free Control

1 Introduction 1.1 内容 上一章是对一个unknown MDP进行value function的预测&#xff0c;相当于policy evaluation。这一章是对unknown MDP找到一个最优的policy&#xff0c; optimise value function. 1.2 On and Off-Policy Learning On-policy learning learn on the…...

MySQL-----事务管理

文章目录 前言一、什么是事务二、为什么会出现事务三、事物的版本支持四、事物的提交方式五、事务常见的操作方式六、事务隔离级别如何理解隔离性1隔离级别查看与设置隔离性读未提交【Read Uncommitted】读提交【Read Committed】可重复读【Repeatable Read】串行化【serializa…...

chatGPT润色中英论文软件-文章修改润色器

chatGPT可以润色英文论文吗&#xff1f; ChatGPT可以润色英文论文&#xff0c;它具备自动纠错、自动完善语法和严格全面的语法、句法和内容结构检查等功能&#xff0c;可以对英文论文进行高质量的润色和优化。此外&#xff0c;ChatGPT还支持学术翻译润色、查重及语言改写等服务…...

MacOS下安装和配置Nginx

一、安装brew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"按回车后&#xff0c;根据提示操作&#xff1a;输入镜像序号 --> 输入Y&#xff0c;回车等待brew安装完成即可。 在终端输入brew -v后&#xff0c;会提示…...

采用UWB(超宽频)技术开发的java版智慧工厂定位系统源码

室内定位系统源码&#xff0c;采用UWB定位技术开发的智慧工厂定位系统源码 技术架构&#xff1a;单体服务 硬件&#xff08;UWB定位基站、卡牌&#xff09; 开发语言&#xff1a;java 开发工具&#xff1a;idea 、VS Code 前端框架&#xff1a;vue 后端框架&#xff1a;s…...

【2023华为OD笔试必会20题--C语言版】《04 日志采集系统》——数组

本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的20道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...

MySQL数据库——MySQL修改存储过程(ALTER PROCEDURE)

在实际开发过程中&#xff0c;业务需求修改的情况时有发生&#xff0c;所以修改 MySQL 中的存储过程是不可避免的。 MySQL 中通过 ALTER PROCEDURE 语句来修改存储过程。下面将详细讲解修改存储过程的方法。 MySQL 中修改存储过程的语法格式如下&#xff1a; ALTER PROCEDURE…...

ASEMI代理ADV7125JSTZ330原装ADI车规级ADV7125JSTZ330

编辑&#xff1a;ll ASEMI代理ADV7125JSTZ330原装ADI车规级ADV7125JSTZ330 型号&#xff1a;ADV7125JSTZ330 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;LQFP-48 批号&#xff1a;2023 引脚数量&#xff1a;48 工作温度&#xff1a;-40C~85C 安装类型&#xff1a;表面…...

86盒IP对讲一键报警器

86盒IP对讲一键报警器 86盒IP对讲一键报警器&#xff1a;革命性保障生命安全的利器&#xff01; 随着科技的飞速发展&#xff0c;我们的生活变得越来越方便和智能化。而86盒IP对讲一键报警器更是在这种背景下应运而生。这款产品不仅无缝对接各种手机APP&#xff0c;也可以在智…...

【高数+复变函数】傅里叶积分

文章目录 【高数复变函数】傅里叶积分2. 傅里叶积分2.1 复数形式积分公式2.2 三角形式 上一节&#xff1a; 【高数复变函数】傅里叶级数 【高数复变函数】傅里叶积分 2. 傅里叶积分 在上一节中&#xff0c;我们知道了傅里叶级数的基本知识&#xff0c;其中&#xff0c;周期为…...

【Leetcode】241. 为运算表达式设计优先级

241. 为运算表达式设计优先级&#xff08;中等&#xff09; 解法一&#xff1a;分治法 对于这道题&#xff0c;加括号其实就是决定运算次序&#xff0c;所以我们可以把加括号转化为&#xff0c;「对于每个运算符号&#xff0c;先执行处理两侧的数学表达式&#xff0c;再处理此…...

torch两个向量除法,对于分母向量中的元素为0是设置为1,避免运算错误

在gpu运行时&#xff0c;如果在进行两个向量除法的时候&#xff0c;对于分母向量中的元素为0是设置为1&#xff0c;避免运算错误。 可以使用torch的division函数以及clamp函数来解决这个问题。具体步骤如下&#xff1a; 使用division函数将分子向量除以分母向量。 使用clamp函…...

NodeJs 最近各版本特性汇总

&#xff08;预测未来最好的方法就是把它创造出来——尼葛洛庞帝&#xff09; NodeJs 官方链接 github链接 V8链接 Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于Chrome V8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模…...

python数据分析案例——天猫订单综合分析

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 什么是数据分析 明确目的–获得数据(爬虫&#xff0c;现有&#xff0c;公开的数据)–数据预处理——数据可视化——结论 准备 环境使用&#xff1a; 在开始写我们的代码之前&#xff0c;我们要准备好运行代码的程序 Anacon…...

05- redis集群模式搭建(上) (包含云服务器[填坑])

目录 1. 准备环境: 2. 简介: -> 2.1 前言: -> 2.2 Redis集群架构实现了对redis的水平扩容 -> 2.3 redis cluster集群原理 3. 搭建后特别需要注意的问题 ->3.1 [重点]: 如果一个服务出现故障: 是否可以继续提供服务??? ---> 3.1.1 如果集群中故障re…...

【AI】YOLOV1原理详解

AI学习目录汇总 0、前言 YOLOv1~3作者是约瑟夫雷德蒙&#xff08;Joseph Chet Redmon&#xff09;&#xff0c;他的网站&#xff1a;https://pjreddie.com/ YOLOv1网站&#xff1a;https://pjreddie.com/darknet/yolov1/ YOLOv2网站&#xff1a;https://pjreddie.com/darknet…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...