你要的react+ts最佳实践指南
本文根据日常开发实践,参考优秀文章、文档,来说说 TypeScript
是如何较优雅的融入 React
项目的。
温馨提示:日常开发中已全面拥抱函数式组件和 React Hooks
,class
类组件的写法这里不提及。
前沿
- 以前有 JSX 语法,必须引入 React。React 17.0+ 不需要强制声明 React 了。
import React, { useState } from 'react';// 以后将被替代成
import { useState } from 'react';
import * as React from 'react';
基础介绍
基本类型
- 基础类型就没什么好说的了,以下都是比较常用的,一般比较好理解,也没什么问题。
type BasicTypes = {message: string;count: number;disabled: boolean;names: string[]; // or Array<string>id: string | number; // 联合类型
}
联合类型
一般的联合类型,没什么好说的,这里提一下非常有用,但新手经常遗忘的写法 —— 字符字面量联合。
- 例如:自定义
ajax
时,一般method
就那么具体的几种:get
、post
、put
等。
大家都知道需要传入一个string
型,你可能会这么写:
type UnionsTypes = {method: string; // ❌ bad,可以传入任意字符串
};
- 使用字符字面量联合类型,第一、可以智能提示你可传入的字符常量;第二、防止拼写错误。后面会有更多的例子。
type UnionsTypes = {method: 'get' | 'post'; // ✅ good 只允许 'get'、'post' 字面量
};
对象类型
- 一般你知道确切的属性类型,这没什么好说的。
type ObjectTypes = {obj3: {id: string;title: string;};objArr: {id: string;title: string;}[]; // 对象数组,or Array<{ id: string, title: string }>
};
- 但有时你只知道是个对象,而不确定具体有哪些属性时,你可能会这么用:
type ObjectTypes = {obj: object; // ❌ bad,不推荐obj2: {}; // ❌ bad 几乎类似 object
};
- 一般编译器会提示你,不要这么使用,推荐使用
Record
。
type ObjectTypes = {objBetter: Record<string, unknown>; // ✅ better,代替 obj: object// 对于 obj2: {}; 有三种情况:obj2Better1: Record<string, unknown>; // ✅ better 同上obj2Better2: unknown; // ✅ any valueobj2Better3: Record<string, never>; // ✅ 空对象/** Record 更多用法 */dict1: {[key: string]: MyTypeHere;};dict2: Record<string, MyTypeHere>; // 等价于 dict1
};
Record
有什么好处呢,先看看实现:
// 意思就是,泛型 K 的集合作为返回对象的属性,且值类型为 T
type Record<K extends keyof any, T> = {[P in K]: T;
};
- 官方的一个例子
interface PageInfo {title: string;
}type Page = 'home' | 'about' | 'contact';const nav: Record<Page, PageInfo> = {about: { title: 'about' },contact: { title: 'contact' },// TS2322: Type '{ about: { title: string; }; contact: { title: string; }; hoem: { title: string; }; }' // is not assignable to type 'Record<Page, PageInfo>'. ...hoem: { title: 'home' },
};nav.about;
好处:
- 当你书写
home
值时,键入h
常用的编辑器有智能补全提示; home
拼写错误成hoem
,会有错误提示,往往这类错误很隐蔽;- 收窄接收的边界。
函数类型
- 函数类型不建议直接给
Function
类型,有明确的参数类型、个数与返回值类型最佳。
type FunctionTypes = {onSomething: Function; // ❌ bad,不推荐。任何可调用的函数onClick: () => void; // ✅ better ,明确无参数无返回值的函数onChange: (id: number) => void; // ✅ better ,明确参数无返回值的函数onClick(event: React.MouseEvent<HTMLButtonElement>): void; // ✅ better
};
可选属性
- React props 可选的情况下,比较常用。
type OptionalTypes = {optional?: OptionalType; // 可选属性
};
- 例子:封装一个第三方组件,对方可能并没有暴露一个 props 类型定义时,而你只想关注自己的上层定义。
name
,age
是你新增的属性,age
可选,other
为第三方的属性集。
type AppProps = {name: string;age?: number;[propName: string]: any;
};
const YourComponent = ({ name, age, ...other }: AppProps) => (<div>{`Hello, my name is ${name}, ${age || 'unknown'}`} <Other {...other} /></div>
);
React Prop 类型
- 如果你有配置
Eslint
等一些代码检查时,一般函数组件需要你定义返回的类型,或传入一些React
相关的类型属性。
这时了解一些React
自定义暴露出的类型就很有必要了。例如常用的React.ReactNode
。
export declare interface AppProps {children1: JSX.Element; // ❌ bad, 没有考虑数组类型children2: JSX.Element | JSX.Element[]; // ❌ 没考虑字符类型children3: React.ReactChildren; // ❌ 名字唬人,工具类型,慎用children4: React.ReactChild[]; // better, 但没考虑 nullchildren: React.ReactNode; // ✅ best, 最佳接收所有 children 类型functionChildren: (name: string) => React.ReactNode; // ✅ 返回 React 节点style?: React.CSSProperties; // React styleonChange?: React.FormEventHandler<HTMLInputElement>; // 表单事件! 泛型参数即 `event.target` 的类型
}
更多参考资料
函数式组件
熟悉了基础的 TypeScript
使用 与 React
内置的一些类型后,我们该开始着手编写组件了。参考 前端进阶面试题详细解答
- 声明纯函数的最佳实践
type AppProps = { message: string }; /* 也可用 interface */
const App = ({ message }: AppProps) => <div>{message}</div>; // 无大括号的箭头函数,利用 TS 推断。
- 需要隐式
children
?可以试试React.FC
。
type AppProps = { title: string };
const App: React.FC<AppProps> = ({ children, title }) => <div title={title}>{children}</div>;
- 争议
React.FC
(orFunctionComponent
)是显式返回的类型,而"普通函数"版本则是隐式的(有时还需要额外的声明)。React.FC
对于静态属性如displayName
,propTypes
,defaultProps
提供了自动补充和类型检查。React.FC
提供了默认的children
属性的大而全的定义声明,可能并不是你需要的确定的小范围类型。- 2和3都会导致一些问题。有人不推荐使用。
目前 React.FC
在项目中使用较多。因为可以偷懒,还没碰到极端情况。
Hooks
项目基本上都是使用函数式组件和 React Hooks
。
接下来介绍常用的用 TS 编写 Hooks 的方法。
useState
- 给定初始化值情况下可以直接使用
import { useState } from 'react';
// ...
const [val, toggle] = useState(false);
// val 被推断为 boolean 类型
// toggle 只能处理 boolean 类型
- 没有初始值(undefined)或初始 null
type AppProps = { message: string };
const App = () => {const [data] = useState<AppProps | null>(null);// const [data] = useState<AppProps | undefined>();return <div>{data && data.message}</div>;
};
- 更优雅,链式判断
// data && data.message
data?.message
useEffect
- 使用
useEffect
时传入的函数简写要小心,它接收一个无返回值函数或一个清除函数。
function DelayedEffect(props: { timerMs: number }) {const { timerMs } = props;useEffect(() =>setTimeout(() => {/* do stuff */}, timerMs),[timerMs]);// ❌ bad example! setTimeout 会返回一个记录定时器的 number 类型// 因为简写,箭头函数的主体没有用大括号括起来。return null;
}
- 看看
useEffect
接收的第一个参数的类型定义。
// 1. 是一个函数
// 2. 无参数
// 3. 无返回值 或 返回一个清理函数,该函数类型无参数、无返回值 。
type EffectCallback = () => (void | (() => void | undefined));
- 了解了定义后,只需注意加层大括号。
function DelayedEffect(props: { timerMs: number }) {const { timerMs } = props;useEffect(() => {const timer = setTimeout(() => {/* do stuff */}, timerMs);// 可选return () => clearTimeout(timer);}, [timerMs]);// ✅ 确保函数返回 void 或一个返回 void|undefined 的清理函数return null;
}
- 同理,async 处理异步请求,类似传入一个
() => Promise<void>
与EffectCallback
不匹配。
// ❌ bad
useEffect(async () => {const { data } = await ajax(params);// todo
}, [params]);
- 异步请求,处理方式:
// ✅ better
useEffect(() => {(async () => {const { data } = await ajax(params);// todo})();
}, [params]);// 或者 then 也是可以的
useEffect(() => {ajax(params).then(({ data }) => {// todo});
}, [params]);
useRef
useRef
一般用于两种场景
-
引用
DOM
元素; -
不想作为其他
hooks
的依赖项,因为ref
的值引用是不会变的,变的只是ref.current
。
- 使用
useRef
,可能会有两种方式。
const ref1 = useRef<HTMLElement>(null!);
const ref2 = useRef<HTMLElement | null>(null);
- 非 null 断言
null!
。断言之后的表达式非 null、undefined
function MyComponent() {const ref1 = useRef<HTMLElement>(null!);useEffect(() => {doSomethingWith(ref1.current);// 跳过 TS null 检查。e.g. ref1 && ref1.current});return <div ref={ref1}> etc </div>;
}
- 不建议使用
!
,存在隐患,Eslint 默认禁掉。
function TextInputWithFocusButton() {// 初始化为 null, 但告知 TS 是希望 HTMLInputElement 类型// inputEl 只能用于 input elementsconst inputEl = React.useRef<HTMLInputElement>(null);const onButtonClick = () => {// TS 会检查 inputEl 类型,初始化 null 是没有 current 上是没有 focus 属性的// 你需要自定义判断! if (inputEl && inputEl.current) {inputEl.current.focus();}// ✅ bestinputEl.current?.focus();};return (<><input ref={inputEl} type="text" /><button onClick={onButtonClick}>Focus the input</button></>);
}
useReducer
使用 useReducer
时,多多利用 Discriminated Unions 来精确辨识、收窄确定的 type
的 payload
类型。
一般也需要定义 reducer
的返回类型,不然 TS 会自动推导。
- 又是一个联合类型收窄和避免拼写错误的精妙例子。
const initialState = { count: 0 };// ❌ bad,可能传入未定义的 type 类型,或码错单词,而且还需要针对不同的 type 来兼容 payload
// type ACTIONTYPE = { type: string; payload?: number | string };// ✅ good
type ACTIONTYPE =| { type: 'increment'; payload: number }| { type: 'decrement'; payload: string }| { type: 'initial' };function reducer(state: typeof initialState, action: ACTIONTYPE) {switch (action.type) {case 'increment':return { count: state.count + action.payload };case 'decrement':return { count: state.count - Number(action.payload) };case 'initial':return { count: initialState.count };default:throw new Error();}
}function Counter() {const [state, dispatch] = useReducer(reducer, initialState);return (<>Count: {state.count} <button onClick={() => dispatch({ type: 'decrement', payload: '5' })}>-</button><button onClick={() => dispatch({ type: 'increment', payload: 5 })}>+</button></>);
}
useContext
一般 useContext
和 useReducer
结合使用,来管理全局的数据流。
- 例子
interface AppContextInterface {state: typeof initialState;dispatch: React.Dispatch<ACTIONTYPE>;
}const AppCtx = React.createContext<AppContextInterface>({state: initialState,dispatch: (action) => action,
});
const App = (): React.ReactNode => {const [state, dispatch] = useReducer(reducer, initialState);return (<AppCtx.Provider value={{ state, dispatch }}><Counter /></AppCtx.Provider>);
};// 消费 context
function Counter() {const { state, dispatch } = React.useContext(AppCtx);return (<>Count: {state.count} <button onClick={() => dispatch({ type: 'decrement', payload: '5' })}>-</button><button onClick={() => dispatch({ type: 'increment', payload: 5 })}>+</button></>);
}
自定义 Hooks
Hooks
的美妙之处不只有减小代码行的功效,重点在于能够做到逻辑与 UI 分离。做纯粹的逻辑层复用。
- 例子:当你自定义 Hooks 时,返回的数组中的元素是确定的类型,而不是联合类型。可以使用 const-assertions 。
export function useLoading() {const [isLoading, setState] = React.useState(false);const load = (aPromise: Promise<any>) => {setState(true);return aPromise.finally(() => setState(false));};return [isLoading, load] as const; // 推断出 [boolean, typeof load],而不是联合类型 (boolean | typeof load)[]
}
- 也可以断言成
tuple type
元组类型。
export function useLoading() {const [isLoading, setState] = React.useState(false);const load = (aPromise: Promise<any>) => {setState(true);return aPromise.finally(() => setState(false));};return [isLoading, load] as [boolean, (aPromise: Promise<any>) => Promise<any>];
}
- 如果对这种需求比较多,每个都写一遍比较麻烦,可以利用泛型定义一个辅助函数,且利用 TS 自动推断能力。
function tuplify<T extends any[]>(...elements: T) {return elements;
}function useArray() {const numberValue = useRef(3).current;const functionValue = useRef(() => {}).current;return [numberValue, functionValue]; // type is (number | (() => void))[]
}function useTuple() {const numberValue = useRef(3).current;const functionValue = useRef(() => {}).current;return tuplify(numberValue, functionValue); // type is [number, () => void]
}
扩展
工具类型
学习 TS 好的途径是查看优秀的文档和直接看 TS 或类库内置的类型。这里简单做些介绍。
- 如果你想知道某个函数返回值的类型,你可以这么做
// foo 函数原作者并没有考虑会有人需要返回值类型的需求,利用了 TS 的隐式推断。
// 没有显式声明返回值类型,并 export,外部无法复用
function foo(bar: string) {return { baz: 1 };
}// TS 提供了 ReturnType 工具类型,可以把推断的类型吐出
type FooReturn = ReturnType<typeof foo>; // { baz: number }
- 类型可以索引返回子属性类型
function foo() {return {a: 1,b: 2,subInstArr: [{c: 3,d: 4,},],};
}type InstType = ReturnType<typeof foo>;
type SubInstArr = InstType['subInstArr'];
type SubIsntType = SubInstArr[0];const baz: SubIsntType = {c: 5,d: 6, // type checks ok!
};// 也可一步到位
type SubIsntType2 = ReturnType<typeof foo>['subInstArr'][0];
const baz2: SubIsntType2 = {c: 5,d: 6, // type checks ok!
};
同理工具类型 Parameters
也能推断出函数参数的类型。
- 简单的看看实现:关键字
infer
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
T extends (...args: any) => infer R ? R : any;
的意思是 T 能够赋值给 (...args: any) => any
的话,就返回该函数推断出的返回值类型 R
。
defaultProps
默认值问题。
type GreetProps = { age: number } & typeof defaultProps;
const defaultProps = {age: 21,
};const Greet = (props: GreetProps) => {// etc
};
Greet.defaultProps = defaultProps;
- 你可能不需要 defaultProps
type GreetProps = { age?: number };const Greet = ({ age = 21 }: GreetProps) => { // etc
};
消除魔术数字/字符
本人比较痛恨的一些代码点。
- 糟糕的例子,看到下面这段代码不知道你的内心,有没有羊驼奔腾。
if (status === 0) {// ...
} else {// ...
}// ...if (status === 1) {// ...
}
- 利用枚举,统一注释且语义化
// enum.ts
export enum StatusEnum {Doing, // 进行中Success, // 成功Fail, // 失败
}//index.tsx
if (status === StatusEnum.Doing) {// ...
} else {// ...
}// ...if (status === StatusEnum.Success) {// ...
}
- ts enum 略有争议,有的人推崇去掉 ts 代码依旧能正常运行,显然 enum 不行。
// 对象常量
export const StatusEnum = {Doing: 0, // 进行中Success: 1, // 成功Fail: 2, // 失败
};
- 如果字符单词本身就具有语义,你也可以用字符字面量联合类型来避免拼写错误
export declare type Position = 'left' | 'right' | 'top' | 'bottom';
let position: Position;// ...// TS2367: This condition will always return 'false' since the types 'Position' and '"lfet"' have no overlap.
if (position === 'lfet') { // 单词拼写错误,往往这类错误比较难发现// ...
}
延伸:策略模式消除 if、else
if (status === StatusEnum.Doing) {return '进行中';
} else if (status === StatusEnum.Success) {return '成功';
} else {return '失败';
}
- 策略模式
// 对象常量
export const StatusEnumText = {[StatusEnum.Doing]: '进行中',[StatusEnum.Success]: '成功',[StatusEnum.Fail]: '失败',
};// ...
return StatusEnumText[status];
相关文章:
你要的react+ts最佳实践指南
本文根据日常开发实践,参考优秀文章、文档,来说说 TypeScript 是如何较优雅的融入 React 项目的。 温馨提示:日常开发中已全面拥抱函数式组件和 React Hooks,class 类组件的写法这里不提及。 前沿 以前有 JSX 语法,…...

软件测试人员会被替代吗?IT行业哪个方向的前景最好?字节12年测开是这样说的
互联网测试从业12年,前来作答。 逻辑上来说,软件工程最初始只需要两个岗位,一个是产品经理。,一个是研发(开发),剩余的 所有岗位都是由他们衍生而来的。 第三个岗位大概率就是测试,…...

十六、vue3.0之富文本编辑器的选择
在工作过程中我们会遇到很多的时候会使用到富文本编辑器,市场上流行的也是各种各样的,那么究竟如何选择呢,今天就给大家讲讲有哪一些,方便大家的选择。 一、TinyMCE TinyMCE 是富文本编辑器领域的头部玩家之一,主流富文本编辑器,功能非常全,你需要的大多数功能它都支持…...

kafka(一) 的架构,各概念
Kafka架构 Kafak 总体架构图中包含多个概念: (1)ZooKeeper:Zookeeper负责保存broker集群元数据,并对控制器进行选举等操作。 (2)Producer: 生产者负责创建消息,将消息发…...
【ts的常用类型】
ts的常用类型前言安装ts常见类型原始类型 、数组、 any变量上的类型注解函数对象类型联合类型类型别名接口接口和类型别名的对比前言 typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验,安装 安装 typescript npm i typescr…...
Hyper-V与安卓模拟器不共存
一是某些新的模拟器已经开始使用新接口开发,支持了共存,安装这种新的安卓模拟器即可。 对于不支持共存的模拟器,只得增加一个windows开机后的系统选项,如果需要切换这两种不同选项使用系统,每次切换都需要重启windows系…...

【图像分类】卷积神经网络之ZFNet网络模型结构详解
写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 1. 前言 由于AlexNet的提出,大型卷积网络开始变得流行起来,但是人们对于网络究竟为什么能表现的这么好,以及怎…...

亿级高并发电商项目-- 实战篇 --万达商城项目 十三(编写购物车、优化修改商品、下架商品方法、购物车模块监听修改商品、删除商品消息)
👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者 📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶 Ǵ…...

springboot 虚拟线程demo
jd19支持虚拟线程,虚拟线程是轻量级的线程,它们不与操作系统线程绑定,而是由 JVM 来管理。它们适用于“每个请求一个线程”的编程风格,同时没有操作系统线程的限制。我们能够创建数以百万计的虚拟线程而不会影响吞吐。 做个 spri…...

CTFer成长之路之逻辑漏洞
逻辑漏洞CTF 访问url: http://1b43ac78-61f7-4b3c-9ab7-d7e131e7da80.node3.buuoj.cn/ 登录页面用随意用户名密码登录 访问url: http://1b43ac78-61f7-4b3c-9ab7-d7e131e7da80.node3.buuoj.cn/user.php 登陆后有商品列表,共三个商品,点击购买flag 钱…...
入门力扣自学笔记238 C++ (题目编号:1144)
1144. 递减元素使数组呈锯齿状 题目: 给你一个整数数组 nums,每次 操作 会从中选择一个元素并 将该元素的值减少 1。 如果符合下列情况之一,则数组 A 就是 锯齿数组: 每个偶数索引对应的元素都大于相邻的元素,即 A…...
蓝桥杯-寒假作业
没有白走的路,每一步都算数🎈🎈🎈 题目描述: 有四个等式,每个等式的运算规则已经定好了,也就是我们常见的小学的四则运算,但是能够用来四则运算的数字非常有限,包括1~13…...

测试用例篇
1.测试用例的意义 测试用例(Test Case)是为了实施测试而向被测试的系统提供的一组集合,这组集合包含:测试环境、操作步骤、测试数据、预期结果等要素。 测试用例的意义是为了帮助测试人员了解测什么,怎么测 eg&#x…...

自动驾驶自主避障概况
文章目录前言1. 自主避障在自动驾驶系统架构中的位置2. 自主避障算法分类2.1 人工势场法(APF)2.1.1引力势场的构建2.1.2斥力势场的构建2.1.3人工势场法的改进2.2 TEB(Timed-Eastic-Band, 定时弹性带)2.3 栅格法2.4 向量场直方图(V…...
Python实用的库排名…
Python 是一个功能强大的编程语言,有着丰富的第三方库和模块,可以帮助你解决各种各样的问题。以下是一些比较厉害的 Python 库: NumPy:一个强大的数值计算库,提供了高效的数组和矩阵操作功能。 Pandas:提供…...

【YOLO系列】YOLOv4论文超详细解读1(翻译 +学习笔记)
前言 经过上一期的开篇介绍,我们知道YOLO之父Redmon在twitter正式宣布退出cv界,大家都以为YOLO系列就此终结的时候,天空一声巨响,YOLOv4闪亮登场!v4作者是AlexeyAB大神,虽然换人了,但论文中给出…...

【神经网络】Transformer基础问答
1.Transforme与LSTM的区别 transformer和LSTM最大的区别就是LSTM的训练是迭代的,无法并行训练,LSTM单元计算完T时刻信息后,才会处理T1时刻的信息,T 1时刻的计算依赖 T-时刻的隐层计算结果。而transformer的训练是并行了࿰…...
制定防火墙策略的步骤和建议
制定防火墙策略是保护企业网络环境安全的关键一步。下面是一些制定防火墙策略的步骤和建议,供参考: 识别网络资产:确定企业网络环境中所有的网络资产,包括服务器、应用程序、数据库、移动设备和终端用户设备等,并进行…...

新必应(New Bing)国内申请与使用教程
微软的新必应(New Bing)基于GPT4模型,比ChatGPT的GPT3.5模型领先半个世代。并且集成了Edge浏览器的数据资源,功能更加强大。经过不断的踩坑,终于申请到了New Bing的使用权限,且国内网络也能够正常使用&…...

博客系统——项目测试报告
目录 前言 博客系统——项目介绍 1、测试计划 1.1、功能测试 1.1.1、编写测试用例 1.1.2、实际执行步骤 1.2、使用Selenium进行Web自动化测试 1.2.1、引入依赖 1.2.2、提取共性,实现代码复用 1.2.3、创建测试套件类 1.2.4、博客登录页自动化测试 1.2.5、…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...