es-toolkit/compat 的 mapKeys 完全指南:Lodash 兼容的对象键映射转换
【免费下载链接】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
mapKeys是 es-toolkit 的 Lodash 兼容层(es-toolkit/compat)中用于"只改键、不改值"地重建对象的工具函数。本文基于 docs/ja/compat/reference/object/mapKeys.md 展开,结合 compat 实现 与 现代版实现 的源码细节,讲解其完整用法、参数约定、iteratee 简写机制与底层原理,帮助你安全地从 lodash 迁移并理解兼容层与原生实现之间的差异。
mapKeys 是什么
mapKeys会遍历对象的每一个自有可枚举字符串键属性,将每个键交给iteratee函数生成新键,并原样保留对应的值,最终返回一个全新的对象。它不会修改传入的原始对象,适合用于键名归一化(如统一为小写、加前缀、加命名空间)或根据值与键的组合生成更语义化的键名。
在es-toolkit/compat中,它的行为与 lodash 的mapKeys保持一致,作为 drop-in replacement 使用:
const result = mapKeys(obj, iteratee);基本用法与典型场景
mapKeys的签名与 lodash 一致:第一个参数是要转换键的对象(或类数组),第二个参数是键转换函数iteratee。
import { mapKeys } from 'es-toolkit/compat';给键添加前缀
const obj = { a: 1, b: 2, c: 3 }; const result = mapKeys(obj, (value, key) => 'prefix_' + key); // 结果: { prefix_a: 1, prefix_b: 2, prefix_c: 3 }将键转换为大写
const data = { name: 'John', age: 30 }; const uppercased = mapKeys(data, (value, key) => key.toUpperCase()); // 结果: { NAME: 'John', AGE: 30 }将数组索引转换为键
object参数接受ArrayLike<T>,因此数组也可以直接传入,iteratee的第二个参数此时为索引:
const arr = ['apple', 'banana', 'orange']; const indexed = mapKeys(arr, (value, index) => `item_${index}`); // 结果: { item_0: 'apple', item_1: 'banana', item_2: 'orange' }组合键与值生成新键
const scores = { math: 90, science: 85, english: 92 }; const detailed = mapKeys(scores, (value, key) => `${key}_score_${value}`); // 结果: { math_score_90: 90, science_score_85: 85, english_score_92: 92 }null 与 undefined 的边界处理
与 lodash 一致,当传入null或undefined时,mapKeys不会抛错,而是将其视为空对象并返回{}:
import { mapKeys } from 'es-toolkit/compat'; mapKeys(null, iteratee); // {} mapKeys(undefined, iteratee); // {}这一行为在 compat 实现 中有直接体现:函数入口处首先执行if (object == null) return {};的判空短路,该判断覆盖null与undefined两种情况。对应测试见 mapKeys.spec.ts。
参数与返回值约定
参数
| 参数 | 类型 | 说明 |
|---|---|---|
object | ArrayLike<T> \| T \| null \| undefined | 需要转换键的对象或数组。null/undefined视为空对象 |
iteratee | ListIteratee<T> \| ObjectIteratee<T>(可选) | 每个键的转换函数,默认值为identity函数(原样返回输入),即不传时键不变 |
其中iteratee回调的调用约定为(value, key, object):第一个参数是当前属性的值,第二个参数是当前键(数组场景下为索引),第三个参数是原对象。
返回值
Record<string, T> | Record<string, T[keyof T]>:返回一个带转换后键的新对象,值保持不变。
深入原理:compat 实现与 iteratee 简写机制
compat 版本的mapKeys是一个非常薄的分发层。其核心逻辑只有两步(见 src/compat/object/mapKeys.ts):
- 判空:
object == null时直接返回{}; - 委托:将对象与经过
iteratee()转换后的回调一并交给现代版mapKeys执行。
iteratee 简写(shorthand)机制
之所以 compat 版"相对较慢",正是因为它需要额外的iteratee转换过程(这也是原文档警告的原因之一)。与 lodash 相同,compat 层的iteratee参数并不限于函数,还支持多种简写形式,由 src/compat/util/iteratee.ts 中的iteratee()工厂函数统一转换:
- 函数:原样返回,直接以
(value, key, object)调用; - 属性名字符串(如
'b'):转换为property(value),即取该属性值作为新键; [属性, 值]二元组:转换为matchesProperty(属性匹配判定);- 部分对象:转换为
matches(对象匹配判定); null/undefined/缺省:转换为identity,即默认保持原键。
这一点有明确的测试佐证。在 mapKeys.spec.ts 中,mapKeys({ a: { b: 'c' } }, 'b')会得到{ c: { b: 'c' } }——这里'b'是属性简写,实际取每个值的b属性(即'c')作为新键。测试还验证了当iteratee为null或undefined时使用identity的默认行为(见 mapKeys.spec.ts)。
对应的类型定义位于 ListIteratee.ts 与 IterateeShorthand.ts,IterateeShorthand<T>展开为PropertyKey | [PropertyKey, any] | PartialShallow<T>,与 lodash 的简写约定完全对齐。
底层核心实现
无论走 compat 层还是直接使用现代版,真正的键转换逻辑都在 src/object/mapKeys.ts:
export function mapKeys<T extends Record<PropertyKey, any>, K extends PropertyKey>( object: T, getNewKey: (value: T[keyof T], key: ObjectKeys<T>, object: T) => K ): Record<K, T[keyof T]> { const result = {} as Record<K, T[keyof T]>; const keys = Object.keys(object) as Array<ObjectKeys<T>>; for (let i = 0; i < keys.length; i++) { const key = keys[i]; const value = object[key]; result[getNewKey(value, key, object)] = value; } return result; }实现思路非常朴素且高效:通过Object.keys获取自有可枚举键,用for循环逐个调用getNewKey生成新键,并把原值写入新对象。它不依赖第三方迭代器,也没有多余的兼容分支,这正是现代版更快的直接原因。
为什么文档建议优先使用现代版mapKeys
原文档在开头给出了明确的::: warning提示:compat 版的mapKeys因为要处理null/undefined判空以及iteratee简写转换过程,相对更慢;如果你的代码不需要 lodash 简写语法与边界兼容,应当优先使用 es-toolkit 原生(现代)版本的mapKeys(日文版见 docs/ja/reference/object/mapKeys.md)。
对比两者:
| 维度 | es-toolkit/compat的mapKeys | es-toolkit原生mapKeys |
|---|---|---|
| 入口 | import { mapKeys } from 'es-toolkit/compat' | import { mapKeys } from 'es-toolkit' |
| null/undefined 容错 | 返回{} | 需自行判空 |
| iteratee 简写(字符串/数组/对象) | 支持(经iteratee()转换) | 仅支持函数 |
| 性能 | 相对较慢(多一层转换与判空) | 更快、更精简 |
需要注意的是,compat 层定位是"与 lodash 100% 行为对齐、可直接替换"(见 src/compat/index.ts),因此它在健壮性与性能之间选择了兼容性优先;而原生版追求的是现代 JavaScript 下的极简与高速。实际项目中,全新代码推荐直接使用原生mapKeys;存量 lodash 代码迁移时则先使用es-toolkit/compat版确保行为一致,再按需逐步替换为原生实现。
总结
es-toolkit/compat的mapKeys完整继承了 lodash 的语义:通过iteratee只转换键、保留值,支持函数回调与多种简写形式,并对null/undefined安全返回空对象。其实现本质是"判空 + iteratee 转换 + 委托原生实现"的薄封装,底层核心算法是Object.keys+ 单次循环。理解这层包装关系,你就能在 lodash 迁移与性能敏感场景之间做出正确选择,并随时可以通过 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),仅供参考