es-toolkit compat 层 constant 函数详解:创建始终返回固定值的函数
【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit
es-toolkit 为兼容 Lodash 使用习惯,在 compat 兼容子包中实现了constant函数:它接收一个值并返回一个闭包,该闭包无论被调用多少次、以何种参数调用,都恒定返回当初传入的那个值。本文基于官方文档 constant (Lodash 互換性) 与仓库源码 src/compat/util/constant.ts,完整讲解constant的签名、类型系统、典型使用场景(高阶函数回调、默认值提供、对象引用保持),并通过测试用例 src/compat/util/constant.spec.ts 印证其对 falsy 值、NaN、调用上下文等边缘行为的实现细节。
读完本文,你将掌握:如何正确导入和使用constant,它与普通箭头函数的取舍,以及源码层面“返回同一对象引用”这一语义是如何保证的。
官方提示:优先使用箭头函数
在展开用法之前,需要先说明文档中一个醒目的告警(原文以::: warning标注):
这个
constant函数会为简单任务创建一个额外的函数包装器,产生不必要的开销。对于这类简单需求,建议使用更简单、更直观的内联箭头函数。
也就是说,如果只是要一个“永远返回固定值”的函数,() => 42这样的内联箭头函数通常更直接。constant的价值在于Lodash 生态的代码迁移兼容,以及在“同一个常量函数被多处复用、传递”的场景中,把创建动作与取值动作分离。理解这一点,才能正确判断何时该用它。
函数签名与类型定义
constant的文档定义如下:
const constantFunction = constant(value);在源码 src/compat/util/constant.ts 中,它通过两个重载声明精确刻画了类型行为:
export function constant<T>(value: T): () => T; export function constant<T>(value?: T): () => T | undefined;两个重载的分工是:
- 当显式传入
value时,第一个重载生效,返回函数类型为() => T——精确锁定为传入值的类型,调用方拿到的是强类型结果; - 当不传参数时,走第二个重载,返回类型退化为
() => T | undefined,调用结果可能是undefined。
文档中的参数与返回值说明与此一致:
参数
value(T,可选):函数要返回的值。不提供时返回undefined。
返回值
() => T | undefined:返回一个始终返回所给值的新函数。
注意参数是可选的,这与部分同类工具“必须传值”的实现不同;下面“不传参数”的行为在测试用例中有专门覆盖。
基本用法:创建一个恒定返回函数
constant适用于“需要一个始终返回特定值的函数”的场景,在函数式编程中常用于提供默认值或作为回调函数。
import { constant } from 'es-toolkit/compat'; // 基本用法 const always42 = constant(42); console.log(always42()); // 42 const alwaysHello = constant('hello'); console.log(alwaysHello()); // "hello"导入路径是es-toolkit/compat,这是 es-toolkit 提供的 Lodash 兼容入口;constant正是通过该入口聚合导出的——在 src/compat/compat.ts 第 277 行可以看到export { constant } from './util/constant.ts'这一导出语句。
结合 map 等高阶函数使用
constant最典型的用途是作为数组map等高阶函数的回调,一次性把所有元素替换为同一个常量。
import { constant } from 'es-toolkit/compat'; // 所有元素填 0 const numbers = [1, 2, 3, 4, 5]; const zeros = numbers.map(constant(0)); console.log(zeros); // [0, 0, 0, 0, 0] // 所有元素替换为同一个对象 const users = ['alice', 'bob', 'charlie']; const defaultUser = users.map(constant({ role: 'user', active: true })); console.log(defaultUser); // [{ role: 'user', active: true }, { role: 'user', active: true }, { role: 'user', active: true }]这个写法在仓库内部也被实际使用:例如 src/compat/util/method.spec.ts 和 src/compat/util/methodOf.spec.ts 中都出现了times(3, constant)这样的组合——用times生成重复值数组时以constant作为迭代回调。而在 src/compat/util/iteratee.spec.ts 中,还能看到values.map(esToolkit.constant(object))的用法,即对一组值批量套用同一个常量函数。
值得一提的是,仓库中cond(条件分支组合函数)的官方示例也依赖constant作为各分支的“返回固定值”动作(见 src/compat/util/cond.ts 的 JSDoc 示例):
const func = cond([ [matches({ a: 1 }), constant('matches A')], [conforms({ b: isNumber }), constant('matches B')], [stubTrue, constant('no match')] ]);作为条件默认值提供器
constant还可以用作默认参数,配合逻辑或运算实现“有值用值、无值回退”的模式:
import { constant } from 'es-toolkit/compat'; function processData(data, fallback = constant('默认值')) { return data || fallback(); } console.log(processData(null)); // "默认值" console.log(processData('实际数据')); // "实际数据"这里constant('默认值')把“默认值”封装成一个可多次求值的函数,调用侧通过fallback()显式取值。这与直接写fallback = '默认值'语义等价,但更贴近 Lodash 风格代码中“回调即接口”的迁移场景。
保持对象引用:返回同一个对象,而非副本
对于对象值,constant返回的不是克隆,而是对原对象的引用保持。这一点有文档示例和测试用例双重佐证:
import { constant } from 'es-toolkit/compat'; const obj = { a: 1 }; const getObj = constant(obj); console.log(getObj() === obj); // true (同一个对象引用)在源码层面,实现就一行核心逻辑(见 src/compat/util/constant.ts 第 24-26 行):
export function constant<T>(value?: T): () => T | undefined { return () => value; }闭包直接捕获形参value,没有任何拷贝或惰性求值,因此每次调用getObj()都返回同一份引用——对引用类型尤其要注意这一点,多处拿到的“同一个对象”是共享状态,修改任意一处会影响其他调用方的结果。
对应的测试 src/compat/util/constant.spec.ts 第一条用例断言了result === object(every检查所有结果都严格等于原对象),与源码行为一致。
测试用例揭示的边缘行为
继续阅读 src/compat/util/constant.spec.ts,可以看到三个值得注意的实现细节:
- 调用上下文与多余参数被完全忽略。测试中先通过
constant(object)创建_constant,然后分别以_constant.call({})(改变this)和_constant(value)(传入多余实参)两种方式调用,断言结果始终=== object。这验证了内部闭包() => value不依赖this、也不读形参的特性——它比很多“具名函数”实现更纯粹的无状态。 - falsy 值全部正确透传。测试使用仓库内部的
falsey数据集(含false、0、''、NaN、null、undefined等)逐一验证constant(value)()的返回结果,并对NaN特判result !== result && value !== value(即NaN === NaN不成立时的相等语义)。也就是说constant(0)()、constant('')()、constant(false)()都能准确返回对应 falsy 值,不会被误判。 - 不传参数时返回
undefined。测试用例index ? constant(value) : constant()覆盖了零参调用路径,与重载声明value?: T的可选语义对应。 - Lodash 的链式(Chaining)支持不在范围内。测试文件尾部明确注释 “Chaining is out of scope for es-toolkit”,
_(true).constant()相关的用例被注释掉了——即 compat 层的constant只做纯函数兼容,不提供 Lodash 链式调用包装,迁移链式代码时需注意这一边界。
与 stub 系列函数的关系
constant是“任意值的通用版”,而仓库 compat 层的 util 目录下还提供了一组固定返回特定值的stub函数(stubTrue、stubFalse、stubObject、stubArray、stubString,参考 src/compat/util/stubTrue.ts 及其对应的文档 docs/ja/compat/reference/util/stubTrue.md 等)。从stubTrue的源码可以看到其返回类型被精确标注为true,这类 stub 函数本质上是constant(true)的特化。当返回类型固定且希望类型系统锁定到字面量时,优先选 stub 系列;当返回任意自定义值时,使用constant。
小结
constant(value)创建一个闭包,恒返回value;参数可选,不传时返回函数结果恒为undefined。- 类型上通过双重载实现:传参时精确推导
() => T,缺参时退化为() => T | undefined。 - 典型场景:
map等高阶函数回调、默认值提供器、cond等组合函数中返回固定分支值;对象值保持同一引用,多处共享同一状态。 - 官方建议:简单场景优先使用内联箭头函数,
constant主要用于 Lodash 迁移兼容与常量函数复用;Lodash 链式用法不在 es-toolkit 的兼容范围内。
相关文档可参考英文版 constant (Lodash Compatibility),实现与测试分别位于 src/compat/util/constant.ts 与 src/compat/util/constant.spec.ts。
【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考