es-toolkit 兼容层 defaultTo 详解:统一处理 null / undefined / NaN 的默认值守卫
【免费下载链接】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
defaultTo是 es-toolkit 为兼容 lodash 而提供的实用函数(位于es-toolkit/compat兼容层),用于在值为null、undefined或NaN时安全地返回兜底默认值。本篇文章以 defaultTo 兼容文档 为核心,结合其 源码实现 与 单元测试,完整讲解它的函数签名、调用约定、典型实战场景(API 响应清洗、数组/对象兜底)以及底层原理,读完即可在项目中直接落地使用。
函数签名与核心行为
defaultTo的调用形式如下:
const result = defaultTo(value, defaultValue);其行为可以一句话概括:当第一个参数是null、undefined或NaN时,返回第二个参数(默认值);否则原样返回第一个参数。它只处理这三类"无效值",而不会拦截false、0、''、空数组[]或空对象{}等 falsy 值——这是它与||运算符、以及??(空值合并运算符)之间最关键的差异。
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
value | T \| null \| undefined | 需要检查的值 |
defaultValue | D | 当value为null、undefined或NaN时返回的默认值 |
返回值
- 类型为
T | D; value有效时返回value本身,否则返回defaultValue。
基础用法示例
import { defaultTo } from 'es-toolkit/compat'; // 基本用法 console.log(defaultTo(null, 'default')); // 'default' console.log(defaultTo(undefined, 'default')); // 'default' console.log(defaultTo(NaN, 0)); // 0 console.log(defaultTo('actual', 'default')); // 'actual' console.log(defaultTo(123, 0)); // 123注意defaultTo(123, 0)返回123而不是0:虽然0是 falsy 值,但123是有效值,函数不会对 falsy 但有效的值做替换。
实战场景一:处理 API 响应中的脏数据
前端最常见的诉求是后端返回的字段可能缺失(undefined)、显式为null,甚至出现NaN。defaultTo可以一次性兜住这三类情况,避免为每种情况分别写判断:
import { defaultTo } from 'es-toolkit/compat'; function processUserData(response) { return { name: defaultTo(response.name, 'No name'), age: defaultTo(response.age, 0), score: defaultTo(response.score, 0), // 包含 NaN 处理 }; } // 当 API 返回不完整数据时 const userData = processUserData({ name: null, age: undefined, score: NaN, }); console.log(userData); // { name: 'No name', age: 0, score: 0 }实战场景二:数组与对象的默认值兜底
defaultTo也常用来为可能缺失的集合类型数据提供安全默认值:
import { defaultTo } from 'es-toolkit/compat'; const users = defaultTo(response.users, []); const metadata = defaultTo(response.metadata, {}); // 只处理 null/undefined/NaN,不处理空数组或空对象 console.log(defaultTo([], ['default'])); // [](空数组也是有效值) console.log(defaultTo({}, { default: true })); // {}(空对象也是有效值)这里的语义是"无效值兜底"而非"空值兜底":即使response.users是空数组、response.metadata是空对象,它们依然会被原样返回,调用方可以在此基础上继续做.map()、.length等操作而无需担心拿到null导致崩溃。
源码级原理剖析
defaultTo的实现非常精简,完整源码位于 src/compat/util/defaultTo.ts:
export function defaultTo<T, D>(value: T | null | undefined, defaultValue: D): T | D { if (value == null || Number.isNaN(value)) { return defaultValue; } return value; }从源码结构可以提炼出几个值得注意的实现细节:
value == null一次覆盖两种值:JavaScript 中==(宽松相等)会同时把null和undefined判定为与null相等,因此这一行就覆盖了两种情形,无需分别=== null和=== undefined。Number.isNaN而非全局isNaN:Number.isNaN(value)是严格版本,只有当value的类型真的是number且值为NaN时才返回true;而全局isNaN会先做类型强制转换,可能把非数字值也误判为NaN。源码选择前者,保证了类型安全。判定条件清晰:只要
value既不等于null/undefined、又不是NaN,就直接返回原值。因此0、false、''、[]、{}等 falsy 但有效的值都不会被替换。函数重载提供类型推断:文件顶部通过 TypeScript 重载声明(src/compat/util/defaultTo.ts)定义了
defaultValue与value类型一致时返回T、不一致时返回T | D两种签名,让调用方在编译期就能获得精确的返回类型推断。
测试如何验证边界行为
src/compat/util/defaultTo.spec.ts 中的测试使用了 compat 内部预置的falsey数组(定义于 src/compat/_internal/falsey.ts):
// src/compat/_internal/falsey.ts export const falsey: unknown[] = [, null, undefined, false, 0, NaN, ''];测试用例把这一整组值逐一传入defaultTo(value, 1),并断言结果等价于value == null || value !== value ? 1 : value:
it('should return a default value if `value` is `NaN` or nullish', () => { const expected = falsey.map(value => (value == null || value !== value ? 1 : value)); const actual = falsey.map(value => defaultTo(value, 1)); expect(actual).toEqual(expected); });这个测试恰好印证了上文总结的行为边界:
null、undefined、NaN→ 返回默认值1;false、0、''、以及稀疏数组中的空槽位 → 原样返回自身,不会被替换。
其中value !== value是利用NaN不等于自身的特性进行检测的等价写法,与源码中Number.isNaN(value)效果一致。
在项目中如何引入
defaultTo通过兼容层统一导出:
- 从
es-toolkit/compat入口导入(与文档示例一致); - 兼容层聚合导出定义于 src/compat/compat.ts,浏览器构建入口 src/browser.ts 同样导出了该函数。
import { defaultTo } from 'es-toolkit/compat';与||、??的取舍建议
在实战中可根据语义选择不同的兜底手段:
| 场景 | 推荐写法 | 说明 |
|---|---|---|
只处理null/undefined | value ?? defaultValue | 原生空值合并,不处理NaN |
需要同时兜住 falsy 值(0、''、false) | value \|\| defaultValue | 会误伤合法的 falsy 值,需谨慎 |
需要统一处理null/undefined/NaN | defaultTo(value, defaultValue) | 兼容 lodash 语义,类型安全 |
defaultTo的价值在于它比??多覆盖了NaN这一难以察觉的"脏值",又比||更克制,不会误伤0、false、''等合法取值。当你的数据源来自 API 响应、用户输入或第三方库时,它是最稳妥的默认值守卫。想了解更多 compat 兼容函数,可参阅 compat 兼容层介绍。
【免费下载链接】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),仅供参考