【React】React学习:从初级到高级(二)
React学习【二】
- 2 添加交互
- 2.1 响应事件
- 2.1.1 添加事件处理函数
- 2.1.2 在事件处理函数中读取`props`
- 2.1.3 将事件处理函数作为`props`传递
- 2.1.4 命名事件处理函数prop
- 2.1.5 事件传播
- 2.1.6 阻止传播
- 2.1.7 传递处理函数作为事件传播的替代方案
- 2.1.8 阻止默认行为
- 2.2 State: 组件的记忆
- 2.2.1 添加一个state变量
- 2.2.2 Hook函数
- 2.2.3 剖析useState
- 2.2.3 赋予一个组件多个state变量
- 2.2.4 State是隔离且私有的
- 2.3 渲染和提交
- 2.4 state在渲染时不会发生更改
- 2.5 把一系列state更新加入队列
- 2.5.1 React会对state更新进行批处理
- 2.5.2 在下次渲染前多次更新同一个state
- 2.5.3 state更新函数的命名惯例
- 2.6 更新state中的对象
- 2.6.1 使用展开语法复制对象
- 2.6.2 使用一个事件处理函数来更新多个字段
- 2.6.3 更新一个嵌套的对象
- 2.6.4 使用Immer编写更简洁的更新逻辑
- 2.7 更新State中的数组
- 2.7.1 更新数组内部的对象
2 添加交互
在 React 中,随时间变化的数据被称为状态(state
)。
2.1 响应事件
事件处理程序是开发者自己写的的函数,它将在用户交互时被触发,如点击、悬停、焦点在表单输入框上等等。
<button>
等内置组件只支持内置浏览器事件,如 onClick
。但是,开发者也可以创建自己的组件,并给它们的事件处理程序 props
指定名称。
2.1.1 添加事件处理函数
如果需要添加一个事件处理函数,需要先定义一个函数,然后将其作为prop
传入合适的JSX标签.
事件处理函数有如下特点:
- 通常在组件内部定义
- 名称以
handle
开头,后跟事件名称
当函数体较短时,内联事件处理函数会很方便。比如:
<button onClick={function handleClick() {alert('你点击了我!');
}}>// 箭头函数
<button onClick={() => {alert('你点击了我!');
}}>
传递给事件处理函数的函数应直接传递<button onClick={handleClick}>
,而非调用<button onClick={handleClick()}>
。加上()
后函数会立即执行,而不是点击按钮时才执行。传递内联函数时,应该将内联事件处理函数包装在匿名函数中。
2.1.2 在事件处理函数中读取props
由于事件处理函数声明于组件内部,因此它们可以直接访问组件的 props。
2.1.3 将事件处理函数作为props
传递
将组件从父组件接收的 prop 作为事件处理函数传递。
function Button({ onClick, children }) {return (<button onClick={onClick}>{children}</button>);
}function PlayButton({ movieName }) {function handlePlayClick() {alert(`正在播放 ${movieName}!`);}return (<Button onClick={handlePlayClick}>播放 "{movieName}"</Button>);
}function UploadButton() {return (<Button onClick={() => alert('正在上传!')}>上传图片</Button>);
}export default function Toolbar() {return (<div><PlayButton movieName="魔女宅急便" /><UploadButton /></div>);
}
2.1.4 命名事件处理函数prop
- 按照惯例,事件处理函数 props 应该以
on
开头,后跟一个大写字母。 - 确保为事件处理程序使用适当的
HTML
标签。
2.1.5 事件传播
如果子组件定义了一个函数,那么在子组件函数被触发后,会向上冒泡到父级组件层级。
在 React 中所有事件都会传播,除了
onScroll
,它仅适用于你附加到的 JSX 标签。
2.1.6 阻止传播
事件处理函数接收一个 事件对象 作为唯一的参数。按照惯例,它通常被称为 e
,代表 “event”(事件)。这个事件对象还允许阻止传播。如果想阻止一个事件到达父组件,需要调用 e.stopPropagation()
。
function Button({ onClick, children }) {return (<button onClick={e => {e.stopPropagation();onClick();}}>{children}</button>);
}export default function Toolbar() {return (<div className="Toolbar" onClick={() => {alert('你点击了 toolbar !');}}><Button onClick={() => alert('正在播放!')}>播放电影</Button><Button onClick={() => alert('正在上传!')}>上传图片</Button></div>);
}
当点击按钮时:
- React 调用了传递给
<button>
的onClick
处理函数。 - 定义在Button中的处理函数执行了如下操作:
- 调用
e.stopPropagation()
,阻止事件进一步冒泡。 - 调用
onClick
函数,它是从Toolbar
组件传递过来的 prop。
- 调用
- 在
Toolbar
组件中定义的函数,显示按钮对应的 alert。 - 由于传播被阻止,父级
<div>
的onClick
处理函数不会执行。
若想对每次点击进行埋点记录,可以通过在事件名称末尾添加
Capture
来实现。<div onClickCapture={() => { /* 这会首先执行 */ }}><button onClick={e => e.stopPropagation()} /><button onClick={e => e.stopPropagation()} /> </div>
每个事件分三个阶段传播:
- 它向下传播,调用所有的
onClickCapture
处理函数。- 它执行被点击元素的
onClick
处理函数。- 它向上传播,调用所有的
onClick
处理函数。捕获事件对于路由或数据分析之类的代码很有用。
2.1.7 传递处理函数作为事件传播的替代方案
此处的点击事件处理函数先执行了一行代码,然后调用了父组件传递的 onClick
prop:
function Button({ onClick, children }) {return (<button onClick={e => {e.stopPropagation();onClick();}}>{children}</button>);
}
也可以在调用父元素 onClick
函数之前,向这个处理函数添加更多代码。
2.1.8 阻止默认行为
某些浏览器事件具有与事件相关联的默认行为。例如,点击 <form>
表单内部的按钮会触发表单提交事件,默认情况下将重新加载整个页面:
export default function Signup() {return (<form onSubmit={() => alert('提交表单!')}><input /><button>发送</button></form>);
}
可以调用事件对象中的 e.preventDefault()
来阻止这种情况。
export default function SignUp() {return (<form onSubmit={e => {e.preventDefault();alert('提交表单!');}}><input /><button>发送</button></form>);
}
e.stopPropagation()
阻止触发绑定在外层标签上的事件处理函数。e.preventDefault()
阻止少数事件的默认浏览器行为。
2.2 State: 组件的记忆
要使用新数据更新组件,需要做两件事:
- 保留 渲染之间的数据。
- 触发 React 使用新数据渲染组件(重新渲染)。
useState
Hook 提供了这两个功能:
- State 变量 用于保存渲染间的数据。
- State setter 函数 更新变量并触发 React 再次渲染组件。
2.2.1 添加一个state变量
import { useState } from 'react'const [index, setIndex] = useState[0];function handleClick() {setIndex(index + 1);
}
2.2.2 Hook函数
在 React 中,useState
以及任何其他以“use
”开头的函数都被称为 Hook。
Hooks ——以
use
开头的函数——只能在组件或自定义 Hook 的最顶层调用。 你不能在条件语句、循环语句或其他嵌套函数内调用 Hook。Hook 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部 “use” React 特性,类似于在文件顶部“导入”模块。
2.2.3 剖析useState
注意:惯例是将这对返回值命名为
const [thing, setThing]
。
useState
的唯一参数是 state 变量的初始值。
每次你的组件渲染时,useState
都会给你一个包含两个值的数组:
- state 变量 (
index
) 会保存上次渲染的值。 - state setter 函数 (
setIndex
) 可以更新 state 变量并触发 React 重新渲染组件。
2.2.3 赋予一个组件多个state变量
可以在一个组件中拥有任意多种类型的 state
变量。
useState
的实现依靠的是数组:在 React 内部,为每个组件保存了一个数组,其中每一项都是一个
state
对。它维护当前state
对的索引值,在渲染之前将其设置为 “0
”。每次调用useState
时,React 都会为你提供一个state
对并增加索引值。
2.2.4 State是隔离且私有的
如果你渲染同一个组件两次,每个副本都会有完全隔离的 state
!改变其中一个不会影响另一个。
与 props
不同,state
完全私有于声明它的组件。
State 变量仅用于在组件重渲染时保存信息。在单个事件处理函数中,普通变量就足够了。当普通变量运行良好时,不要引入 state 变量。比如:
export default function FeedbackForm() {function handleClick() {const name = prompt('What is your name?');alert(`Hello, ${name}!`);}return (<button onClick={handleClick}>Greet</button>);
}
2.3 渲染和提交
React请求和提供UI的过程总共包括三个步骤:
- 触发渲染
- 组件的 初次渲染。
- 组件(或者其祖先之一)的 状态发生了改变。
- 渲染组件
- 在进行初次渲染时, React 会调用根组件
root
。 - 对于后续的渲染, React 会调用那些使内部状态更新从而触发渲染的函数组件。
- 在进行初次渲染时, React 会调用根组件
- 提交到DOM
- 对于初次渲染, React 会使用
appendChild()
DOM API 将其创建的所有 DOM 节点放在屏幕上。 - 对于重复渲染, React 将只执行必要渲染操作,以使得 DOM节点 与最新的渲染输出结果匹配一致。
- 对于初次渲染, React 会使用
2.4 state在渲染时不会发生更改
一个 state 变量的值永远不会在一次渲染的内部发生变化, 即使其事件处理函数的代码是异步的。
2.5 把一系列state更新加入队列
2.5.1 React会对state更新进行批处理
React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。
比如
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
组件的重新渲染只会发生在这三次setNumber()
调用之后。
2.5.2 在下次渲染前多次更新同一个state
若多次更新同一个state
,React
会将每一次state
的更新状态存入队列,并把最后的结果更新到state
中。这称为批处理。
以下是可以考虑传递给 setNumber
state 设置函数的内容:
- 一个更新函数(例如:
n => n + 1
)会被添加到队列中。 - 任何其他的值(例如:数字
5
)会导致“替换为5
”被添加到队列中,已经在队列中的内容会被忽略。
2.5.3 state更新函数的命名惯例
通常可以通过相应 state 变量的第一个字母来命名更新函数的参数,也可以用更明晰的命名:
setEnabled(e => !e);
setLastName(ln => ln.reverse());
setFriendCount(fc => fc * 2);
2.6 更新state中的对象
应该 把所有存放在 state 中的 JavaScript 对象都视为只读的。在改变state时,不能改变state中现有的对象,要重新创建一个对象把原来的对象替换掉。比如下面两种写法是正确且等价的:
// 第一种
const nextPosition = {};
nextPosition.x = e.clientX;
nextPosition.y = e.clientY;
setPosition(nextPosition);// 第二种
setPosition({x: e.clientX,y: e.clientY
});
2.6.1 使用展开语法复制对象
通常,你会希望把 现有 数据作为你所创建的新对象的一部分。例如,你可能只想要更新表单中的一个字段,其他的字段仍然使用之前的值。那么此时就可以用展开语法...
import { useState } from 'react';export default function Form() {const [person, setPerson] = useState({firstName: 'Barbara',lastName: 'Hepworth',email: 'bhepworth@sculpture.com'});function handleFirstNameChange(e) {setPerson({...person,firstName: e.target.value});}function handleLastNameChange(e) {setPerson({...person,lastName: e.target.value});}function handleEmailChange(e) {setPerson({...person,email: e.target.value});}return (<><label>First name:<inputvalue={person.firstName}onChange={handleFirstNameChange}/></label><label>Last name:<inputvalue={person.lastName}onChange={handleLastNameChange}/></label><label>Email:<inputvalue={person.email}onChange={handleEmailChange}/></label><p>{person.firstName}{' '}{person.lastName}{' '}({person.email})</p></>);
}
请注意 ...
展开语法本质是是“浅拷贝”——它只会复制一层。这使得它的执行速度很快,但是也意味着当你想要更新一个嵌套属性时,你必须得多次使用展开语法。
2.6.2 使用一个事件处理函数来更新多个字段
import { useState } from 'react';export default function Form() {const [person, setPerson] = useState({firstName: 'Barbara',lastName: 'Hepworth',email: 'bhepworth@sculpture.com'});function handleChange(e) {setPerson({...person,[e.target.name]: e.target.value // 重点是这里,使用 DOM 元素的 name属性});}return (<><label>First name:<inputname="firstName"value={person.firstName}onChange={handleChange}/></label><label>Last name:<inputname="lastName"value={person.lastName}onChange={handleChange}/></label><label>Email:<inputname="email"value={person.email}onChange={handleChange}/></label><p>{person.firstName}{' '}{person.lastName}{' '}({person.email})</p></>);
}
在这里,e.target.name
引用了 <input>
这个 DOM 元素的 name
属性。
2.6.3 更新一个嵌套的对象
如果对象拥有多层嵌套,那么可以创建新的对象:
const nextArtwork = { ...person.artwork, city: 'New Delhi' };
const nextPerson = { ...person, artwork: nextArtwork };
setPerson(nextPerson);
或者写成一个函数调用:
setPerson({...person, // 复制其它字段的数据 artwork: { // 替换 artwork 字段 ...person.artwork, // 复制之前 person.artwork 中的数据city: e.target.value // 但是将 city 的值替换为 New Delhi!}
});
对象并非真正嵌套,只是属性"指向"彼此而已。
2.6.4 使用Immer编写更简洁的更新逻辑
由
Immer
提供的draft
是一种特殊类型的对象,被称为 Proxy,它会记录你用它所进行的操作。从原理上说,Immer
会弄清楚draft
对象的哪些部分被改变了,并会依照你的修改创建出一个全新的对象。
使用Immer
:
- 运行
npm install use-immer
添加Immer
依赖 - 用
import { useImmer } from 'use-immer'
替换掉import { useState } from 'react'
import { useImmer } from 'use-immer';export default function Form() {const [person, updatePerson] = useImmer({name: 'Niki de Saint Phalle',artwork: {title: 'Blue Nana',city: 'Hamburg',image: 'https://i.imgur.com/Sd1AgUOm.jpg',}});function handleNameChange(e) {updatePerson(draft => {draft.name = e.target.value;});}function handleTitleChange(e) {updatePerson(draft => {draft.artwork.title = e.target.value;});}function handleCityChange(e) {updatePerson(draft => {draft.artwork.city = e.target.value;});}function handleImageChange(e) {updatePerson(draft => {draft.artwork.image = e.target.value;});}return (<><label>Name:<inputvalue={person.name}onChange={handleNameChange}/></label><label>Title:<inputvalue={person.artwork.title}onChange={handleTitleChange}/></label><label>City:<inputvalue={person.artwork.city}onChange={handleCityChange}/></label><label>Image:<inputvalue={person.artwork.image}onChange={handleImageChange}/></label><p><i>{person.artwork.title}</i>{' by '}{person.name}<br />(located in {person.artwork.city})</p><img src={person.artwork.image} alt={person.artwork.title}/></>);
}
为什么在 React 中不推荐直接修改 state?
- 调试时使用
console.log()
可以很容易发现前后两次渲染发生了什么变化.- React常见的优化策略依赖于如果之前的
props
或者state
的值和下一次相同就跳过渲染。- 如果用户需求变更,可以很容易恢复到以前的版本。
2.7 更新State中的数组
同对象一样,当想要更新存储于 state
中的数组时,需要创建一个新的数组(或者创建一份已有数组的拷贝值),并使用新数组设置 state
。
当操作 React state 中的数组时,需要避免使用左列能改变原数组的方法,而首选右列能返回一个新数组的方法:
避免使用(会改变原始数组) | 推荐使用(返回一个新数组) | |
---|---|---|
添加元素 | push /unshift | concat /[...arr] 展开语法 |
删除元素 | pop /shift /splice | filter /slice |
替换元素 | splice /arr[i]=...赋值 | map |
排序 | reverse /sort | 先将数组复制一份、toSorted |
或者使用Immer
。
2.7.1 更新数组内部的对象
即使拷贝了数组,还是不能直接修改其内部的元素。这是因为数组的拷贝是浅拷贝——新的数组中依然保留了与原始数组相同的元素。
比如这样就不行:
const nextList = [...list];
nextList[0].seen = true; // 问题:直接修改了 list[0] 的值
setList(nextList);
正确的做法是再次拷贝一份,然后进行修改,我们可以使用map
函数:
setMyList(myList.map(artwork => {if (artwork.id === artworkId) {// 创建包含变更的*新*对象return { ...artwork, seen: nextSeen };} else {// 没有变更return artwork;}
}));
或者使用更简洁的immer
:
updateMyTodos(draft => {const artwork = draft.find(a => a.id === artworkId);artwork.seen = nextSeen;
});
增
最简单的一种就是使用 ...
数组展开 语法:
setArtists( // 替换 state[ // 是通过传入一个新数组实现的...artists, // 新数组包含原数组的所有元素{ id: nextId++, name: name } // 并在末尾添加了一个新的元素]
);
数组展开运算符还允许你把新添加的元素放在原始的 ...artists
之前:
setArtists([{ id: nextId++, name: name },...artists // 将原数组中的元素放在末尾
]);
这样一来,展开操作就可以完成 push()
和 unshift()
的工作,将新元素添加到数组的末尾和开头.
删
从数组中删除一个元素最简单的方法就是将它过滤出去。可以通过 filter
方法实现:
// 使用filter方法删除元素
setArtists(artists.filter(a =>a.id !== artist.id)
);
改
如果想改变数组中的某些或全部元素,可以先用 map()
创建一个新数组。再使用新的数组进行重新渲染。
import { useState } from 'react';let initialShapes = [{ id: 0, type: 'circle', x: 50, y: 100 },{ id: 1, type: 'square', x: 150, y: 100 },{ id: 2, type: 'circle', x: 250, y: 100 },
];export default function ShapeEditor() {const [shapes, setShapes] = useState(initialShapes);function handleClick() {const nextShapes = shapes.map(shape => {if (shape.type === 'square') {// 不作改变return shape;} else {// 返回一个新的圆形,位置在下方 50px 处return {...shape,y: shape.y + 50,};}});// 使用新的数组进行重渲染setShapes(nextShapes);}return (<><button onClick={handleClick}>所有圆形向下移动!</button>{shapes.map(shape => (<divkey={shape.id}style={{background: 'purple',position: 'absolute',left: shape.x,top: shape.y,borderRadius:shape.type === 'circle'? '50%' : '',width: 20,height: 20,}} />))}</>);
}
插入元素
向数组特定位置插入一个元素。可以将数组展开运算符 ...
和 slice()
方法一起使用。
function handleClick() {const insertAt = 1; // 可能是任何索引const nextArtists = [// 插入点之前的元素:...artists.slice(0, insertAt),// 新的元素:{ id: nextId++, name: name },// 插入点之后的元素:...artists.slice(insertAt)];setArtists(nextArtists);setName('');}
其他改变数组中元素的情况,可以先拷贝这个数组,再改变这个拷贝后的值。
相关文章:
![](https://www.ngui.cc/images/no-images.jpg)
【React】React学习:从初级到高级(二)
React学习【二】 2 添加交互2.1 响应事件2.1.1 添加事件处理函数2.1.2 在事件处理函数中读取props2.1.3 将事件处理函数作为props传递2.1.4 命名事件处理函数prop2.1.5 事件传播2.1.6 阻止传播2.1.7 传递处理函数作为事件传播的替代方案2.1.8 阻止默认行为 2.2 State: 组件的记…...
![](https://img-blog.csdnimg.cn/7b24ae8c2bfb4ee79efdc8526e397eac.png)
无法将类型为“Newtonsoft.Json.Linq.JObject”的对象转换为类型“Newtonsoft.Json.Linq.JArray”解决方法
对于“Newtonsoft.Json.Linq.JObject”的对象强制类型转换为类型“Newtonsoft.Json.Linq.JArray”报错 第一的图为对象{“*************”:“********”} 第二个图片为数组[{“…”:“…”}] 在我这里进行强制转换对象转换为类型“Newtonsoft.Json.Linq.JArray”报错. 那我们…...
![](https://img-blog.csdnimg.cn/img_convert/cf18ac649249f426c9f7f61b1d8f641a.png)
从零开始,无需公网IP,搭建本地电脑上的个人博客网站并发布到公网
文章目录 前言1. 安装套件软件2. 创建网页运行环境 指定网页输出的端口号3. 让WordPress在所需环境中安装并运行 生成网页4. “装修”个人网站5. 将位于本地电脑上的网页发布到公共互联网上 前言 在现代社会,网络已经成为我们生活离不开的必需品,而纷繁…...
![](https://www.ngui.cc/images/no-images.jpg)
Excel VSTO开发6 -Range对象
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 6 Range对象 Excel中最重要的一个对象是Range对象,它可以代表某一单元格、某一行、某一列、某一区域(该区域…...
![](https://img-blog.csdnimg.cn/ad2eb1ccdc96457f9a4de2d9281070d5.png)
LeetCode 15 三数之和
题目链接 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目解析 // 1. 排序双指针 // 2. 固定一个值nums[i] 然后去剩下的位置去找 两数之和符合nums[j]nums[k]是否等于-nums[i] // 3. 细节问题:由于题目中是不可以包含重复的三元组的…...
![](https://img-blog.csdnimg.cn/img_convert/1984c819004571f237d62c906c9567e4.png)
车船边缘网关是如何给车辆船只定位的?
随着智能交通系统的不断发展,车路协同成为了重要的研究方向之一。而AI边缘计算网关在这个领域中发挥着至关重要的作用。本文将重点介绍AI边缘计算网关在车路协同中的应用,并强调其中的重点词汇或短语。 首先,什么是AI边缘计算网关࿱…...
![](https://img-blog.csdnimg.cn/7b01a213fca54b29ad7d8078093c1a4b.png)
详解MAC帧、ARP、DNS、ICMP协议
局域网通信原理 比如新建了一个内网,如果一台机器A找机器B,封FRAME时(OSI的第二层用的数据格式),要封装对方的MAC,开始时A不知道B的MAC,只知道IP,它就发一个ARP包,源IP是…...
![](https://img-blog.csdnimg.cn/8dcd81b928644539982e10371d9360f2.png)
Leetcode:【169. 多数元素】
题目 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 难度:简单 题目链接:169. 多数元素 示例 1ÿ…...
![](https://www.ngui.cc/images/no-images.jpg)
好用免费的Chat GPT
MindLink麦灵 你问我答 灵感 持续更新中。。。。...
![](https://www.ngui.cc/images/no-images.jpg)
MySQL-MHA
目录 1、什么是 MHA 2、MHA 的组成 3、MHA 的特点 3.1 MHA工作原理总结如下 4、搭建 MySQL MHA 4.1 实验环境配置 MHA架构 故障模拟 4.2 安装MHA所有组件 4.3 故障模拟 4.4 总结 1、什么是 MHA MHA(MasterHigh Availability)是一套优秀的My…...
![](https://img-blog.csdnimg.cn/0a436b74ac5f4b2182bfcef402b6c066.png)
初识Node.js与内置模块
1. 初识 Node.js 1.1 回顾与思考 1. 已经掌握了哪些技术 2. 浏览器中的 JavaScript 的组成部分 3. 思考:为什么 JavaScript 可以在浏览器中被执行 4. 思考:为什么 JavaScript 可以操作 DOM 和 BOM 5. 浏览器中的 JavaScript 运行环境 6. 思考ÿ…...
![](https://img-blog.csdnimg.cn/62ce392b44c04ffe8c89c674f5639121.png)
NLP(1)--NLP基础与自注意力机制
目录 一、词向量 1、概述 2、向量表示 二、词向量离散表示 1、one-hot 2、Bag of words 3、TF-IDF表示 4、Bi-gram和N-gram 三、词向量分布式表示 1、Skip-Gram表示 2、CBOW表示 四、RNN 五、Seq2Seq 六、自注意力机制 1、注意力机制和自注意力机制 2、单个输出…...
![](https://img-blog.csdnimg.cn/a7aa0f371afa4fd789dae132b230bb54.png)
Ubuntu 升级cuda版本与切换
下载cuda版本 进:CUDA Toolkit 12.2 Downloads | NVIDIA Developer wget https://developer.download.nvidia.com/compute/cuda/12.2.0/local_installers/cuda_12.2.0_535.54.03_linux.runsudo sh ./cuda_12.2.0_535.54.03_linux.run --toolkit --silent --overrid…...
![](https://img-blog.csdnimg.cn/46132c48ad004f99a90a1d16630a589d.png)
精讲算法的时间复杂度
目录 一、算法效率 1.算法效率 1.1如何衡量一个算法的好坏 1.2算法的复杂度 二、时间复杂度 1.时间复杂度的概念 2.大O的渐进表示法 3.常见时间复杂度的计算举例 三、空间复杂度 一、算法效率 1.算法效率 1.1如何衡量一个算法的好坏 long long Fib(int N) {if(N <…...
![](https://img-blog.csdnimg.cn/img_convert/d0c2462eb37bb188a353ec04b9d3c69e.png)
java八股文面试[多线程]——newWorkStealingPool
newWorkStealingPool是什么? newWorkStealingPool简单翻译是任务窃取线程池。 newWorkStealingPool 是Java8添加的线程池。和别的4种不同,它用的是ForkJoinPool。 使用ForkJoinPool的好处是,把1个任务拆分成多个“小任务”,把这…...
![](https://img-blog.csdnimg.cn/5f9545fc5c284f7cb2bc6739c24aae50.png)
STM32--RTC实时时钟
文章目录 Unix时间戳时间戳转换BKPRTC简介RTC框图硬件电路RTC的注意事项RTC时钟实验工程 Unix时间戳 Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。 时间戳存储在一个秒计数器中,秒计数器为32位/64…...
![](https://www.ngui.cc/images/no-images.jpg)
【N2】例题学习笔记
N2例题 《新"日本语能力测试"例题集》 听力原稿(PDF) 【10】 【問い】この筆者から見た「仕事ができる人」の特徴はどんなことか。 【提问】这位作者认为,仕事能力强的人具有什么特点呢? 【11】 文章 下の文章は、企業のあり方について…...
![](https://img-blog.csdnimg.cn/img_convert/3c5bbaa45bef35e5abd373f41ac8384a.webp?x-oss-process=image/format,png)
【数据分享】2006-2021年我国城市级别的道路、桥梁、管线建设相关指标(10多项指标)
《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况,在之前的文章中,我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国城市级别的市政设施水平相关指标、2006-2021年我国城市级别的各类建设用地面积数…...
![](https://www.ngui.cc/images/no-images.jpg)
视觉SLAM14讲笔记-第7讲-视觉里程计2
直接法的引出 直接法是视觉里程计另一个主要分支,它与特征点法有很大的不同。 使用特征点法估计相机运动时,我们把特征点看作固定在三维空间的不动点。根据它们在相机中的投影位置,通过最小化重投影误差来优化相机运动。 相对地,…...
![](https://www.ngui.cc/images/no-images.jpg)
MySQL——单行函数和分组函数
2023.9.3 单行函数的SQL语句学习笔记如下: #常见单行函数介绍(部分省略) #字符函数 #将姓变大写,名变小写,然后拼接。 SELECT CONCAT(UPPER(last_name), ,LOWER(first_name)) AS 姓名 FROM employees; # 姓名中首字符…...
![](https://img-blog.csdnimg.cn/fc7d420a48464bcf803e5371d569080d.png)
百度百科词条怎么更新?怎么能顺利更新百科词条?
企业和个人百度百科词条的更新对于他们来说都具有重要的意义,具体如下: 对企业来说: 塑造品牌形象:百度百科是一个常被用户信任并参考的知识平台,通过更新企业词条可以提供准确、全面的企业信息,帮助企业塑…...
![](https://img-blog.csdnimg.cn/img_convert/c7aa8a707882a1c3167fffb2d4bccf42.jpeg)
PPT怎么转换为PDF格式,收藏这两个在线工具。
PPT是一种常用的演示文稿格式,它可以包含丰富的动画效果和超链接,让你的内容更加生动和有趣。但是,如果你想将PPT分享给别人,或者在不同的设备上查看,你可能会遇到一些问题,比如: PPT文件太大&a…...
![](https://www.ngui.cc/images/no-images.jpg)
八大排序算法----堆排序
堆排序的基本步骤:(以从大到小的顺序排序为例) 1.构建大顶堆(每个结点的值都大于或等于其左右孩子结点的值) 2.排序:每次堆顶的元素取出来(整个堆中值最大),与最后一个…...
![](https://img-blog.csdnimg.cn/a0ea18bcf37643b6b1f8d1f4ed32def9.png)
Docker Desktop 设置镜像环境变量
点击run 展开Optional settings container name :容器名称 Ports:根据你需要的端口进行输入,不输入则默认 后面这个 比如我这个 5432 Volumes:卷,也就是做持久化 需要docker 数据保存的地方 Environment variables…...
![](https://img-blog.csdnimg.cn/01dce98cc9654a22b69d1f3512546162.png)
springboot之一:配置文件(内外部配置优先顺序+properties、xml、yaml基础语法+profile动态切换配置、激活方式)
配置的概念: Spring Boot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。 注意配置文件的命名必须是applicat…...
![](https://img-blog.csdnimg.cn/4208314195954c949e262ac0c302d10a.jpeg#pic_center)
涛然自得周刊(第 5 期):蝲蛄吟唱的地方
作者:何一涛 日期:2023 年 8 月 20 日 涛然自得周刊主要精选作者阅读过的书影音内容,不定期发。历史周刊内容可以看这里。 电影 《沼泽深处的女孩》 改编自小说《蝲蛄吟唱的地方》,主角是一位在沼泽地独自生活并长大的女孩&…...
![](https://img-blog.csdnimg.cn/62fe41845e954e62a9510d76eaa76433.gif#pic_center)
Android Ble蓝牙App(七)扫描过滤
Ble蓝牙App(七)扫描过滤 前言目录正文一、增加菜单二、使用MMKV① 添加依赖② 封装MMKV③ 使用MMKV 三、过滤空设备名四、过滤Mac地址五、过滤RSSI六、源码 前言 在上一篇文章中了解了MTU的相关知识以及对于设备操作信息的展示,本篇文章中将增…...
![](https://www.ngui.cc/images/no-images.jpg)
小程序当前页面栈以及跳转
1.调用页面栈刷新接口 let pages getCurrentPages(); //当前页面栈 if (pages.length > 1) { let beforePage pages[pages.length - 2]; //获取上一个页面实例对象 beforePage.$vm.getActivityLi…...
![](https://www.ngui.cc/images/no-images.jpg)
jQuery获取表单的值val()
(1)页面中有很多元素,包括表单中的输入项,如输入文本框等;获取、设置、输入文本框的值;val()方法。 (2)也包括<p>、<span>等元素;获取、设置这些元素的文本…...
![](https://img-blog.csdnimg.cn/c3068d9cff664423a0242e659177b882.png)
【专栏必读】数字图像处理(MATLAB+Python)专栏目录导航及学习说明
文章目录 第一章:绪论第二章:数字图像处理基础第三章:图像基本运算第四章:图像的正交变换第五章:图像增强第六章:图像平滑第七章:图像锐化第八章:图像复原第九章:图像形态…...
![](https://img-blog.csdnimg.cn/img_convert/637c06e21c5ed56faaa121ade8e5fa13.png)
东莞微联建站/商业计划书
媒体报道的消息显示,金立前总裁卢伟冰加入小米,同时小米宣布旗下品牌红米改名为Redmi并独立运营,有分析认为卢伟冰可能将负责红米品牌,并巩固红米品牌在国际市场的竞争优势,而小米品牌则专注于高端手机市场。小米这一做…...
![](https://images.cnblogs.com/cnblogs_com/gnielee/WindowsLiveWriter/Office2007_D316/regedit_thumb.png)
如何在服务器上搭建网站/免费网页制作网站
当点击邮件中附件时,Outlook可以对附件进行预览(如下图),如果将“Always warn before previewing this type of file”选项点掉后,每次预览该类型文件时则不再提示,大大方便了预览效果。 可是有时又需要Out…...
![](/images/no-images.jpg)
北京专业建设/优化推广服务
一 搭建篇yum install -y subversionsvnserve --version二 创建项目仓库mkdir /var/svncd /var/svnsvnadmin create /var/svn/[项目名]三 配置项目仓库cd /var/svn/[项目名]/conf1.修改综合配置vi svnserve.conf//找到以下配置项,将前面的#号去掉,然后做…...
![](http://hi.csdn.net/attachment/201112/1/0_1322708778u3rs.gif)
贵阳免费网站建设/企业营销策划
转载地址:http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html java中的多线程 在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。 对于直接继承Thread的类来说,代…...
![](/images/no-images.jpg)
.net作业做网站/计算机培训机构
未开始待续...未完待续......
![](http://acm.hdu.edu.cn/data/images/C40-1003-1.jpg)
石家庄网站开发费用/网络营销外包收费
骨牌铺方格 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 747 Accepted Submission(s): 479 Problem Description在2n的一个长方形方格中,用一个1 2的骨牌铺满方格,输入n ,输出铺放方案的总数.例如n3时,为2 3方格&…...