es-toolkit/compat 中的 sample 函数:从数组、对象与字符串中随机取值的兼容实现详解

发布时间:2026/9/15 11:44:12
es-toolkit/compat 中的 sample 函数:从数组、对象与字符串中随机取值的兼容实现详解 es-toolkit/compat 中的 sample 函数从数组、对象与字符串中随机取值的兼容实现详解【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkitsample是 es-toolkit 兼容层es-toolkit/compat中用于从集合中随机取出一个元素的核心工具函数。本文以 docs/compat/reference/array/sample.md 为骨架结合 compat 实现源码、底层 数组版 sample 与其 测试用例完整讲解它的用法、边界行为、参数与返回值并深入到源码调用链说明它为什么比原生es-toolkit的sample慢以及你应该在什么场景下选择哪一个版本。一、sample是什么sample从一个数组array或对象object中获取一个随机元素。对数组而言它返回数组中的某个随机元素对对象而言它返回对象中的某个随机值value而非 key。它同时兼容 lodash 的调用习惯因此在 es-toolkit 中位于兼容入口es-toolkit/compat并作为src/array/index.ts第 44 行与src/compat/compat.ts中的导出成员对外暴露。const randomItem sample(collection);值得特别注意的是兼容版sample支持的数据形态比原生版更广数组、类数组、字符串、对象、null、undefined这是以一定性能开销为代价换来的——这一点在 原文档 开头就有明确警告下文会详细展开。二、基本用法从数组取样import { sample } from es-toolkit/compat; // 从数组中随机取一个元素 sample([1, 2, 3, 4, 5]); // 返回 1 到 5 之间的随机一个数字从对象取样import { sample } from es-toolkit/compat; // 从对象中随机取一个值 sample({ a: 1, b: 2, c: 3 }); // 返回 1、2、3 中的随机一个值字符串也能取样import { sample } from es-toolkit/compat; // 字符串同样支持 sample(hello); // 返回 h、e、l、l、o 中的随机一个字符null与undefined的处理当传入null或undefined时函数返回undefined而不是抛出异常import { sample } from es-toolkit/compat; sample(null); // undefined sample(undefined); // undefined这一点在 compat 源码 中体现为入口处的空值短路判断if (collection null) { return undefined; }同时测试用例 也专门验证了对空集合取样返回undefined这一行为——它对empties空值集合逐个调用sample期望所有结果均为undefined。参数与返回值根据 原文档 及源码中的重载签名src/compat/array/sample.ts参数collectionArrayLikeT | Recordstring, T | null | undefined要进行取样的数组或对象。类型层面还额外提供了readonly [T, ...T[]]非空元组与T extends object任意对象两个重载以便在编译期获得更精确的推断。返回值T | string | undefined从数组或对象中随机选出的一个元素当集合为空、或传入null、undefined时返回undefined。三、源码级原理一次取样的完整调用链兼容版sample的实现非常精简全部逻辑集中在 src/compat/array/sample.tsexport function sampleT(collection: ArrayLikeT | Recordstring, T | null | undefined): T | string | undefined { if (collection null) { return undefined; } if (isArrayLike(collection)) { return sampleToolkit(toArray(collection)); } return sampleToolkit(Object.values(collection)); }第一步空值短路collection null同时覆盖null与undefined直接返回undefined避免后续操作报错。这也是兼容版相比原生版多出来的一次空值检查开销。第二步区分类数组与普通对象isArrayLikesrc/compat/predicate/isArrayLike.ts用于判断集合是否类数组export function isArrayLike(value?: any): boolean { return value ! null typeof value ! function isLength((value as ArrayLikeunknown).length); }它要求值非空、不是函数并且length属性是合法长度。而合法长度由 src/compat/predicate/isLength.ts 判定export function isLength(value?: any): boolean { return Number.isSafeInteger(value) (value as number) 0; }即length必须是非负的安全整数Number.isSafeInteger校验这意味着真实数组、字符串、arguments对象、带有数字下标与length的类数组对象都会被判定为类数组——这也解释了为什么sample(hello)能返回单个字符。第三步统一转为数组后交给原生实现对于类数组先通过 src/compat/_internal/toArray.ts 归一化为数组export function toArrayT(value: ArrayLikeT): T[] { return Array.isArray(value) ? value : Array.from(value); }对于普通对象则直接取Object.values(collection)得到值的数组。两条分支最终都调用原生 src/array/sample.tsexport function sampleT(arr: readonly T[]): T { const randomIndex Math.floor(Math.random() * arr.length); return arr[randomIndex]; }随机性的核心只有两行用Math.random()生成[0, 1)的浮点数乘以数组长度后向下取整得到落在合法下标范围内的随机索引再按下标取值。整体时间复杂度为 O(n)对象/字符串需要先转数组字符串的Array.from还会逐字符拆分空间复杂度同样为 O(n)。测试如何验证随机性compat 的测试 通过结果必须属于原集合来验证取样的正确性而不是断言具体值数组测试expect(array).toContain(actual)对象测试把结果与Object.values(object)比对字符串测试把结果与[a, b, c]比对空值测试对empties逐一断言返回undefined。此外原生数组版测试 采用expect(arr.includes(sample(arr))).toBe(true)的等价写法。这套测试模式很适合复用到你自己的随机逻辑验证中。四、为什么文档建议优先使用原生sample原文档 在开篇就放置了醒目的警告兼容版sample由于null/undefined处理、对象值处理等逻辑运行速度较慢建议优先使用更快的、更现代的 es-toolkit 原生sample。从源码可以清晰地印证这一判断维度原生samplesrc/array/sample.ts兼容版samplesrc/compat/array/sample.ts输入形态仅readonly T[]数组、类数组、字符串、对象、null、undefined空值处理无需调用方保证非空入口处一次 null短路判断类型分发无isArrayLikeisLength双重判定归一化无直接按下标取类数组走toArray对象走Object.values额外开销Math.random() 取整 取值在上述基础上叠加判断与数组转换也就是说兼容版为了兼容 lodash 的宽泛输入约定在每次调用中额外付出了类型判定与集合转换的开销而原生版针对数组这一唯一形态做了极简实现。如果你已经确定输入是数组直接用 原生sample即可获得最干净的性能表现只有当你的代码需要无差别处理对象、字符串与空值、且与 lodash 行为保持一致时才需要es-toolkit/compat的版本。五、小结sample用于从集合中随机取一个元素兼容版支持数组、对象、字符串null/undefined返回undefined核心随机逻辑只有Math.floor(Math.random() * arr.length)一行原生实现 极其轻量兼容版的慢来自 src/compat/array/sample.ts 中的空值检查、isArrayLike判定与toArray/Object.values转换属于为了兼容 lodash 输入约定而付出的必要成本相关源码与测试均可继续深入阅读兼容实现、原生实现、兼容测试、类数组判定、长度判定、toArray 工具。如果你只需要从数组中取随机元素请直接参考更快的 es-toolkit 原生 sample 文档。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考