ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

es-toolkit 的 cond 函数:用函数式风格编排多条件分支的 Lodash 兼容实现

es-toolkit 的 cond 函数:用函数式风格编排多条件分支的 Lodash 兼容实现 es-toolkit 的 cond 函数用函数式风格编排多条件分支的 Lodash 兼容实现【免费下载链接】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导读cond是 es-toolkit 兼容层es-toolkit/compat提供的一个工具函数它接收一组条件-动作函数对返回一个新的复合函数按顺序逐个求值条件命中第一个为真的条件时执行其对应的动作函数并返回结果若全部条件均为假则返回undefined。本文以 cond 官方文档 为主体结合 cond 源码实现、单元测试 与 性能基准讲清它的用法、类型签名、底层工作原理、与 Lodash 的兼容行为以及官方文档明确提示的性能注意点帮助你判断何时该用、何时不该用。一、核心概念什么是condcond(pairs)接收一个由[predicate, func]二元组组成的数组返回一个新函数。调用该新函数时它会把收到的参数依次交给每个predicate条件谓词求值一旦某个谓词返回真值就调用同组的func动作函数并直接返回其结果如果所有谓词都为假则返回undefined。const conditionFunction cond(pairs);在函数式风格中cond相当于一个可组合的 if-else 链它把离散的条件分支封装成一个可传递、可复用的值让调用方无需关心分支细节只需调用conditionFunction(...args)。注意es-toolkit 的cond只存在于es-toolkit/compat兼容入口中使用前需从该路径导入import { cond } from es-toolkit/compat;二、基础用法按顺序匹配条件官方文档给出的第一个场景是按数值区间返回不同标签。cond从数组第一个二元组开始依次判断命中即返回因此条件的书写顺序直接决定优先级import { cond } from es-toolkit/compat; // Basic usage const getValue cond([ [x x 10, x big], [x x 5, x medium], [x x 0, x small], [() true, () zero or negative], ]); console.log(getValue(15)); // big console.log(getValue(8)); // medium console.log(getValue(3)); // small console.log(getValue(-1)); // zero or negative这里最后一个[() true, () zero or negative]是一个兜底分支由于() true恒为真任何在前面分支中未命中的输入都会落入此处等效于 else 子句。这种前分支写具体条件、末位写恒真兜底是使用cond的典型模式。关键语义只执行第一个命中的分支cond与普通 if-else 链一样是短路的——一旦某个条件为真后续分支不再求值且只有第一个命中的动作函数会被执行。官方文档用下面这个例子验证这一点import { cond } from es-toolkit/compat; const checkValue cond([ [x x 10, x greater than 10], [x x 5, x less than 5], ]); console.log(checkValue(15)); // greater than 10 console.log(checkValue(3)); // less than 5 console.log(checkValue(7)); // undefined (no matching condition)当输入7时两个条件都不满足函数返回undefined。这一行为在 cond.spec.ts 中有专门测试cond([[stubFalse, stubA]])传入任意对象都会得到undefined因为stubFalse恒为假。三、进阶用法对象模式匹配cond的谓词并不仅限于数值比较它接受任意谓词函数因此天然适合做对象字段的模式匹配——把角色判断 字符串格式化这类逻辑收敛进一张规则表import { cond } from es-toolkit/compat; const processUser cond([ [user user.role admin, user Admin: ${user.name}], [user user.role user, user User: ${user.name}], [user user.role guest, user Guest: ${user.name}], [() true, () Unknown role], ]); console.log(processUser({ name: John, role: admin })); // Admin: John console.log(processUser({ name: Jane, role: user })); // User: Jane这种写法的价值在于规则表本身是一个可配置、可动态构建的数据结构你可以把pairs数组存起来、按需重组或由外部配置驱动比硬编码的 if-else 更灵活代价则是可读性与性能的取舍详见第五节。四、类型签名与参数说明根据 cond 源码该函数提供两组重载签名// 无参调用形式谓词与动作都不接收输入参数 export function condR(pairs: Array[truthy: () boolean, falsey: () R]): () R; // 接收一个输入值的形式谓词与动作共享同一个输入 export function condT, R(pairs: Array[truthy: (val: T) boolean, falsey: (val: T) R]): (val: T) R;项目说明pairsArray[predicate, func]由条件函数 动作函数组成的二元组数组predicate条件函数接收调用参数返回布尔值真值即命中func动作函数命中对应条件后执行其返回值作为整个调用的结果返回值(...args: any[]) unknown一个新的复合函数全部条件不命中时返回undefined值得注意的底层细节虽然重载签名限制为无参或单参但实际实现export function cond(pairs: any[][]): (...args: any[]) unknown会对任意数量的参数求值并且谓词与动作函数会收到完全相同的参数。这一点由 cond.spec.ts 验证调用resultFunc(a, b, c)时谓词和动作函数都收到[a, b, c]。参数校验与this绑定实现中还有两个容易被忽略的行为均有测试佐证动作函数必须为函数类型构造时若pair[1]不是函数如false、true会直接抛出TypeError(Expected a function)。见 cond.ts 与对应测试 cond.spec.ts。校验在构造阶段进行而不是调用阶段。this透传生成的复合函数会保留调用方的this上下文谓词与动作函数均通过predicate.apply(this, args)/func.apply(this, args)调用。测试 cond.spec.ts 展示了一个利用this取属性值的场景。谓词简写iteratee的自动转换这是cond与 Lodash 兼容的关键点之一。源码中每个谓词都会经过iteratee(predicate)归一化处理见 cond.ts而 iteratee 实现 支持以下输入形式函数原样返回直接作为谓词属性名如c转换为取该属性的函数真值即命中属性-值二元组如[b, 1]转换为属性值是否等于给定值的判断matchesProperty部分对象如{ a: 1 }转换为对象是否匹配该部分对象的判断matches。因此你可以把文档示例中的函数谓词写成简写形式测试 cond.spec.ts 验证了这种写法与函数写法行为完全一致const resultFunc cond([ [{ a: 1 }, () a], // 对象简写 → matches({ a: 1 }) [[b, 1], () b], // 属性-值简写 → matchesProperty(b, 1) [c, () c], // 属性名简写 → property(c) ]);五、性能注意官方明确建议优先使用 if-else / switchcond文档开头带有一段醒目的 warning这是本文最需要认真对待的工程建议由于复杂的 iteratee 处理、数组变换和函数校验cond函数运行较慢。建议改用更快、更清晰的 if-else 或 switch 语句。从源码看这个警告并非空穴来风性能开销主要来自三处见 cond.ts构造阶段的开销pairs.map(...)对每一对执行isFunction校验并调用iteratee做谓词归一化生成新的processedPairs数组调用阶段的间接层每次调用都要经predicate.apply/func.apply动态分发且谓词是经过包装的 iteratee比直接写if (x 10)多一层函数调用数组遍历条件匹配是线性扫描for循环最坏情况无命中需要遍历全部二元组。仓库 benchmarks/performance/cond.bench.ts 中同时用es-toolkit/compat/cond与lodash/cond各跑 100ms 的基准用例覆盖命中第一个、第二个、第三个分支及全部未命中四种输入如果你关心与 Lodash 的量化差异可以在本仓库运行性能基准自行对比。因此实践上的选择标准是热路径、性能敏感、分支逻辑稳定直接用 if-else 或 switch可读性和性能都更好规则表可配置、需要动态组装分支、或追求函数式组合cond是合理选择但要意识到它带来的间接调用开销兜底分支习惯上用() true或stubTrue作为最后一个二元组模拟 else 语义避免返回意外的undefined。六、兼容定位与测试保障cond是 es-toolkit 的 Lodash 兼容实现从 compat 入口 导出与 lodash 的_.cond保持一致的语义条件按顺序求值、只执行第一个命中分支、全不命中返回undefined、支持matches/matchesProperty/property等谓词简写、动作函数非函数时抛TypeError。上述行为在 cond.spec.ts 中共有 6 组用例覆盖条件组合、参数透传、谓词简写、无命中返回 undefined、TypeError 校验、this 绑定可作为迁移到 es-toolkit 时的行为对照清单。总结cond为函数式风格的多条件分支提供了一种紧凑、可组合、可配置的写法支持函数谓词与 Lodash 风格的简写谓词且严格遵循顺序匹配、短路执行、全不命中返回 undefined的语义。但在使用前请记住文档中的明确警告它比 if-else / switch 更慢、间接层更多适合规则表驱动的场景而不适合性能敏感的冷热路径。理解 cond.ts 的实现细节iteratee 归一化、构造期校验、this 透传能帮助你在兼容性与性能之间做出正确的工程取舍。【免费下载链接】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),仅供参考
返回列表