一些常见的工具函数

作为一名现代前端开发人员,除了掌握框架(React/Vue/Next.js等)和构建工具(Vite/Webpack),你还需要熟练掌握或手写一大批实用工具函数(Utils),这些函数几乎出现在每一个中大型项目中。

下面是一张目前最常用、最值得掌握的前端工具函数分类表格(2025~2026主流实践):

分类函数名称/功能作用/典型使用场景推荐掌握程度是否建议自己手写一次常用替代库
类型判断isObject / isPlainObject判断纯对象(排除null、数组、Date等)★★★★★Lodash.isPlainObject
类型判断isEmpty / isNil判断空值(null/undefined/空对象/空数组/空字符串)★★★★★Lodash/Ramda
类型判断isBrowser / isServer判断当前运行环境(浏览器/服务端)★★★★
防抖/节流debounce / throttle搜索框、resize、scroll、按钮狂点等★★★★★强烈建议手写lodash.debounce
深拷贝deepClone / structuredClone对象/数组深拷贝(支持循环引用更好)★★★★★是(至少掌握一种)lodash.cloneDeep
对象操作omit / pick从对象中删除/保留指定字段★★★★Lodash
对象操作merge / deepMerge对象深度合并(常用于配置合并)★★★★Lodash.merge
数组操作unique / uniqBy数组去重(基础/根据字段)★★★★Lodash
数组操作groupBy / countBy数组分组/计数★★★建议Lodash
字符串处理capitalize / camelCase / kebabCase首字母大写 / 驼峰 / 连字符转换★★★★Lodash
字符串处理truncate / ellipsis字符串截断加省略号★★★
函数式工具once / memoize函数只执行一次 / 记忆函数★★★★Lodash
URL/参数getQueryParam / parseUrl / stringifyQuery获取/解析/序列化URL参数★★★★★qs
CookiegetCookie / setCookie / removeCookiecookie读写删除(兼容性处理)★★★★js-cookie
Storagestorage.get / storage.set(带过期)localStorage/sessionStorage 带过期时间★★★★
时间日期formatDate / relativeTime / dayDiff日期格式化 / 多久前 / 相差几天★★★★date-fns / dayjs
随机randomId / uuid / randomString生成唯一id / 随机字符串★★★★uuid / nanoid
颜色处理hexToRgb / rgbToHex / lightenColor颜色格式转换 / 亮度调整★★★视项目而定tinycolor2
设备/浏览器isMobile / isWechat / getOS判断移动端/微信/操作系统★★★★bowser / ua-parser
性能优化requestIdleCallback polyfill空闲时执行任务★★★了解即可
事件相关on / off / once(事件总线)简易自定义事件★★★建议mitt / tiny-emitter
错误处理tryCatch / safeJsonParse安全JSON.parse / 带try-catch的函数执行★★★
Promisesleep / retry / timeout / parallelLimit延迟 / 重试 / 超时 / 限制并发★★★★是(至少sleep+retry)p-limit / retry

快速掌握优先级建议

  1. debounce / throttle
  2. deepClone(至少掌握JSON.parse + 递归两种方式)
  3. isEmpty / isNil / isPlainObject
  4. getQueryParam / stringifyQuery
  5. formatDate / relativeTime
  6. once / memoize
  7. randomId / uuid
  8. omit / pick
  9. unique / uniqBy
  10. sleep / retry

推荐学习路径(实用建议)

这些函数看似简单,但真正能又快又稳地写出来,并且考虑边界情况、类型安全、性能的同学,在面试和实际项目中都非常吃香。

你现在最想先掌握/手写哪个分类的函数?可以告诉我,我给你出个手写题或参考实现~ 🚀

debounce / throttle

我对防抖和节流,真的是没有搞清楚,用法没有搞清楚、实现更没有搞清楚。原因在于我不知道二者到底有什么区别?是怎么实现的?实现之后的效果到底是什么?

我好像笼统的认为,都是隔一段时间之后再执行,二者好像没有区别啊?2020年作用收集的司徒正美的一篇文章,感觉也没有讲清楚。干脆直接问AI吧,结果AI一下子就抓住了重点。

防抖(Debounce)和节流(Throttle)的目的都是限制函数在短时间内被过于频繁地调用,但它们的策略和使用场景完全不同

用最生活化的比喻来帮你一次搞懂两者的区别:

比喻场景防抖(Debounce)节流(Throttle)核心区别
你在电梯门口狂按按钮只会在你最后一次按完过了一段时间才发车每隔几秒强制发一次车,不管你按多少次防抖等你停手,节流强制间隔
搜索框输入关键词你停下来不打字了才去发请求(最后一次输入后)你边打边搜,但每秒最多搜一次防抖等安静,节流匀速放行
拖拽调整窗口大小拖完松手才重新计算布局拖拽过程中每隔200ms计算一次布局防抖只认最后,节流要中间结果
鼠标疯狂快速移动只在你停下来后才记录最后的位置每隔一段时间就记录一次当前位置防抖只取终点,节流要过程点
像不像疯狂发微信消息一直发一直不显示,等你停几秒才一次性发出一直发,但每秒最多只显示一条
最终触发次数通常只触发1次(最后一次)可触发多次,但频率被严格控制次数差别很大
典型等待时间感“你再等等我,我等你彻底停下来再说”“你随便按,我每隔几秒给你处理一次”体验完全不同

直观对比表(最常用的场景)

场景防抖(Debounce)合适吗?节流(Throttle)更合适吗?推荐选择
搜索框输入后发请求★★★★★(强烈推荐)★★防抖
窗口resize事件★★★★★★★★看需求(大多数用节流)
鼠标滚轮/触屏滑动★★★★★★★(强烈推荐)节流
按钮疯狂点击(防止重复提交)★★★★★★★防抖
拖拽元素实时跟随鼠标★★★★★节流
input change 频繁校验★★★★★★★多数用防抖
页面滚动加载更多★★★★★★★节流

代码最直观的对比(动画感理解)

一句话总结目前最容易记住的区别:

防抖 = “等你消停了再说” → 适合“最后一次才重要”的场景 节流 = “别太快,我要喘口气” → 适合“过程需要持续采样”的场景

防抖和节流最终执行的是哪一次触发的函数呢?

我觉得这个是我最没有搞清楚的地方,只要搞清楚了这个,写代码实现就很容易了。

防抖(debounce)和节流(throttle)最终执行的是哪一次触发的函数?

这是一个非常容易混淆但又很核心的区别,下面用最直白的方式对比说明:

情况防抖(debounce)最终执行的是哪一次节流(throttle)最终执行的是哪一次形象比喻
事件连续快速触发很多次最后一次(你停手后的那一次)每隔固定时间段内的第一次(或最后一次,看实现)防抖:等你按完电梯才发车
节流:每分钟发一班车
假设间隔 300ms只在最后一次触发后等 300ms 才执行大约每 300ms 执行一次(取决于 leading/trailing)
典型例子:输入框搜索你停下来不打字后的那次输入你打字过程中每隔 300ms 取一次当前输入防抖等你安静
节流边打边采样
典型例子:窗口 resize拖完窗口松手后的那次尺寸拖动过程中每隔 300ms 取一次当前尺寸防抖只认最终
节流要中间结果
假设连续触发 10 次只执行第 10 次可能执行 3~4 次(看间隔和持续时间)
事件停止后是否还会执行会(延迟后执行最后一次)取决于 trailing 设置(通常会补最后一次)

两种最常见的实现方式对比(最终执行哪一次)

快速对照表(最终执行的是哪一次)

实现方式最终执行的是哪一次调用常见使用场景
debounce(trailing)最后一次搜索框、表单校验、保存按钮
throttle(只 leading)每段间隔的第一滚动加载、鼠标移动跟踪
throttle(只 trailing)每段间隔的最后一次某些 resize 场景
throttle(leading + trailing)第一 + 最后(中间丢弃)大多数现代 UI 组件库的默认节流

一句话总结区别(背下来最有用):

希望这次解释能让你彻底分清「到底执行的是哪一次」~ 如果还有具体场景不确定执行的是哪一次,可以举例告诉我,我帮你分析!

动画演示

tanstack/react-pacer提供了很多实用的工具函数,我使用里面提供的防抖、节流函数来演示一下效果。这篇blog写的也很好,动画可以看一下https://kettanaito.com/blog/debounce-vs-throttle

debounce

这是没有加防抖的情况,输入框每次变动,都会请求一次数据。

这是加了防抖的,只有在输入停止1s之后才会请求数据。

throttle

可以看到,节流的实际效果就是每隔一段时间执行一次,不需要停止下来之后才能执行。

React 面试最常考的 8 个工具函数/Hooks

下面是简洁的表格概览,后面会逐一详细讲解作用、使用场景、核心原理、手写代码,帮助你真正理解和记住。

序号名称核心作用一句话总结考察频率手写难度
1debounce / throttle控制函数执行频率,防止高频事件卡顿/浪费资源★★★★★中等
2useDebounceReact 中安全防抖一个值★★★★★中等
3usePrevious获取上一次渲染的值★★★★☆低-中等
4deepClone完整深拷贝对象(处理循环引用)★★★★中等
5useMemoizedFn创建永不变化的函数引用★★★★中等
6useUpdate强制触发组件重渲染★★★★
7get (safe get)安全访问深层嵌套属性★★★★低-中等
8once让函数只被执行一次★★★

1. debounce / throttle

详细作用

典型真实场景(非常详细)

核心区别(背下来) debounce = “等你消停了再说”(只执行最后一次) throttle = “别太快,我要喘口气”(固定节奏执行,过程有采样)

2. useDebounce

详细作用 在 React 中对进行防抖处理,返回一个延迟更新的版本。 核心目的:避免值频繁变化导致 useEffect、API 调用、渲染等副作用频繁执行。

典型场景

3. usePrevious

详细作用 记住组件上一次渲染时的值,让你在当前渲染周期内可以拿到“旧值”进行对比。

典型场景

4. deepClone

详细作用 创建对象的完整独立副本,修改副本不会影响原对象,支持数组、嵌套对象、循环引用。

典型场景

5. useMemoizedFn

详细作用 创建一个引用永远不变的函数,但内部永远执行最新传入的函数体。 解决了 useCallback 必须依赖 deps 数组,导致函数引用频繁变化的问题。

典型场景

6. useUpdate

详细作用 不修改任何状态的情况下,强制触发组件重新渲染

典型场景

7. get(安全访问深层属性)

详细作用 安全地访问对象深层属性,任意一层为 null/undefined 都不会报错,并可提供默认值。

典型场景

8. once

详细作用 保证一个函数在整个生命周期(或指定范围内)只被执行一次,之后调用都返回第一次的结果。

典型场景

如果你准备面试,这些函数建议按照以下优先级手写练习:

  1. debounce + throttle + useDebounce(几乎必考)
  2. usePrevious + useMemoizedFn(非常高频)
  3. deepClone + get(经典手写题)
  4. useUpdate + once(加分项)

需要我针对其中某一个再给出更详细的面试回答模板常见追问吗?