es-toolkit/compat 中的 mapKeys深入解析 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本文聚焦 es-toolkit 的 Lodash 兼容层es-toolkit/compat中mapKeys函数的完整使用方式与底层实现。mapKeys用于在保持对象值不变的前提下通过迭代函数对每个键进行转换并生成新对象适用于键规范化、加前缀、大小写转换等场景。阅读本文后你将掌握兼容版mapKeys的参数类型、迭代器简写shorthand语法、与 es-toolkit 原生版本的差异以及源码级的实现原理。概述mapKeys创建一个新对象它遍历源对象的所有自有可枚举字符串键把每个键交给迭代函数iteratee变换变换结果作为新对象的键而值保持不变。const result mapKeys(obj, iteratee);在兼容层中该函数挂在es-toolkit/compat入口下import { mapKeys } from es-toolkit/compat;为什么文档推荐优先使用 es-toolkit 原生 mapKeys在阅读 兼容版 mapKeys 文档 时首先会看到一条醒目的警告兼容版mapKeys相对较慢原因是它需要处理null或undefined输入并承担迭代器iteratee转换流程的开销。文档明确建议在常规场景下改用 es-toolkit 原生、更快的mapKeys从es-toolkit/object导入。两者的取舍在于es-toolkit/object的原生mapKeys实现精简、类型精确、性能更好适合现代 JavaScript 项目es-toolkit/compat的兼容mapKeys完整复刻 Lodash 的行为语义包括空值兜底、迭代器简写、数组类对象支持适合从 Lodash 迁移或需要保持旧代码行为的场景。基本用法mapKeys(object, iteratee)使用iteratee函数变换对象的每个键从而创建新对象。值保持不变只有键被修改。适用于对象的键转换与规范化。import { mapKeys } from es-toolkit/compat; // 为键添加前缀 const obj { a: 1, b: 2, c: 3 }; const result mapKeys(obj, (value, key) prefix_ key); // Result: { prefix_a: 1, prefix_b: 2, prefix_c: 3 } // 将键转换为大写 const data { name: John, age: 30 }; const uppercased mapKeys(data, (value, key) key.toUpperCase()); // Result: { NAME: John, AGE: 30 } // 将数组下标转换为键 const arr [apple, banana, orange]; const indexed mapKeys(arr, (value, index) item_${index}); // Result: { 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}); // Result: { 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); // {}这一行为由 兼容版源码 中的空值检查保证export function mapKeys(object: any, getNewKey: ListIterateeany identity): Recordstring, any { if (object null) { return {}; } return mapKeysToolkit(object, iteratee(getNewKey)); }object null同时覆盖null与undefined注意这里用的是宽松相等判断对应测试 mapKeys.spec.ts 中的两个用例。参数与返回类型参数objectArrayLikeT | T | null | undefined要转换键的对象或数组。兼容版同时接受普通对象和数组类对象见下文“把数组当作对象处理”。iterateeListIterateeT | ObjectIterateeT可选用于变换每个键的函数默认为identity函数即原样返回输入。返回Recordstring, T | Recordstring, T[keyof T]返回一个键已转换的新对象。若object为数组类对象返回Recordstring, T若为普通对象返回Recordstring, T[keyof T]。值得注意的是兼容版的重载声明支持两种输入形态见 src/compat/object/mapKeys.ts// 数组类对象重载迭代函数收到 (value, index, collection) export function mapKeysT(object: ArrayLikeT | null | undefined, iteratee?: ListIterateeT): Recordstring, T; // 普通对象重载迭代函数收到 (value, key, object) export function mapKeysT extends object( object: T | null | undefined, iteratee?: ObjectIterateeT ): Recordstring, T[keyof T];迭代函数的三类参数与简写语法完整函数形式在兼容版中迭代函数会接收到(value, key, object)三个参数——分别是当前属性值、当前键或数组下标以及整个源对象。与原生版一致最后一个参数object可用于基于整个对象上下文生成新键mapKeys({ a: 1, b: 2 }, (value, key, object) ${key}_${Object.keys(object).length});迭代器简写Iteratee Shorthand兼容版的最大卖点之一是支持 Lodash 风格的迭代器简写。iteratee参数的完整类型定义见 ListIteratee.tsexport type ListIterateeT | ((value: T, index: number, collection: ArrayLikeT) unknown) | (PropertyKey | [PropertyKey, any] | PartialShallowT);也就是说除了函数iteratee还可以是属性名PropertyKey从值中取出指定属性作为新键属性-值对[PropertyKey, any]判断值是否满足指定属性值部分对象PartialShallow判断值是否匹配部分对象的属性。这些简写由iteratee()工具统一转换见 src/compat/util/iteratee.tsswitch (typeof value) { case function: return value as any; case object: if (Array.isArray(value) value.length 2) { return matchesProperty(value[0], value[1]); } return matches(value); default: return property(value); }测试 mapKeys.spec.ts 验证了属性名简写的行为it(should work with _.property shorthands, () { const actual mapKeys({ a: { b: c } }, b); expect(actual).toEqual({ c: { b: c } }); });这里iteratee传字符串b表示“取每个值的b属性作为新键”于是{ a: { b: c } }被转换为{ c: { b: c } }。默认 identity当iteratee缺省、为null或undefined时兼容版通过iteratee(getNewKey)内部的空值分支回退到identity见 src/compat/util/iteratee.ts键保持不变。测试 mapKeys.spec.ts 专门覆盖了这一场景验证传入null、undefined或省略参数时结果一致。源码级实现从兼容层到原生层兼容版mapKeys本身并不重复实现遍历逻辑而是把脏活交给原生版自己只做两件事空值兜底与迭代器归一化见 src/compat/object/mapKeys.ts若object null直接返回{}调用iteratee(getNewKey)把函数或简写统一转换成标准迭代函数委托给原生mapKeysToolkit(object, iteratee(getNewKey))完成实际遍历。原生实现位于 src/object/mapKeys.tsexport function mapKeysT extends RecordPropertyKey, any, K extends PropertyKey( object: T, getNewKey: (value: T[keyof T], key: ObjectKeysT, object: T) K ): RecordK, T[keyof T] { const result {} as RecordK, T[keyof T]; const keys Object.keys(object) as ArrayObjectKeysT; 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(object)获取所有自有可枚举字符串键符号键会被排除数字键会被转换为字符串参见 ObjectKeys 类型定义使用普通for循环逐项调用getNewKey(value, key, object)把返回值作为新对象的键值保持不变返回全新的对象不修改源对象符合纯函数的语义。这也解释了兼容版性能偏慢的原因多了一层iteratee()转换的运行时开销。如果不需要简写语法、也不用兼容null/undefined输入原生版会更轻量。把数组当作对象处理兼容版文档与测试都确认数组会被当作对象来遍历下标即键。测试 mapKeys.spec.ts 中的用例it(should treat arrays like objects, () { const actual mapKeys(array, String); expect(actual).toEqual({ 1: 1, 2: 2 }); });对于[1, 2]String把下标0、1转换为字符串键得到{ 1: 1, 2: 2 }。前面示例中mapKeys(arr, (value, index) \item_${index})能生成{ item_0: apple, ... }正是基于同一机制。导出入口兼容版mapKeys通过 src/compat/compat.ts 统一导出export { mapKeys } from ./object/mapKeys.ts;因此可直接使用import { mapKeys } from es-toolkit/compat;引入与其他 Lodash 兼容函数共用同一入口。使用建议小结场景推荐导入理由现代项目、追求性能es-toolkit/object的mapKeys无空值/简写开销类型更精确从 Lodash 迁移、需要行为完全一致es-toolkit/compat的mapKeys支持空值兜底、迭代器简写、数组类对象实际使用时按需选择即可需要 Lodash 兼容语义尤其是iteratee简写与null/undefined兜底时选兼容版其余情况优先考虑 原生 mapKeys 以获得更好的性能与类型体验。【免费下载链接】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),仅供参考