资讯详情

资讯详情

es-toolkit/compat 的 keys 函数:兼容 Lodash 的自有可枚举属性名获取指南

es-toolkit/compat 的 keys 函数兼容 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 兼容层es-toolkit/compat中的keys函数展开它用于返回对象自身可枚举属性名的字符串数组与 Lodash 的_.keys行为保持一致。文中将完整覆盖其基本用法、继承属性过滤、类数组对象特殊处理、空值安全语义并结合仓库源码与测试用例深入剖析其底层实现原理帮助你在迁移 Lodash 时准确使用该 API并理解它与原生Object.keys()的性能差异。一、函数定位兼容 Lodash 的keys但优先推荐Object.keyskeys是 es-toolkit 兼容层提供的 Lodash 兼容函数官方文档在介绍它时首先给出了一条明确的警告这个keys函数由于包含对类数组对象、原型对象等的复杂处理逻辑运行速度较慢。请优先使用更快、更现代的Object.keys()。也就是说keys的存在意义是帮助从 Lodash 平滑迁移的兼容 API而不是日常开发的首选工具。如果你没有 Lodash 迁移负担直接用原生Object.keys()即可获得更好的性能如果你的代码库中大量使用了_.keys(object)则可以将es-toolkit/compat的keys作为直接替换品两者行为基本一致。该函数定义于 src/compat/object/keys.ts并通过 compat 入口 统一导出export { keys } from ./object/keys.ts;二、安装与导入keys属于 es-toolkit 的兼容层模块需要从es-toolkit/compat子路径导入import { keys } from es-toolkit/compat;注意es-toolkit/compat与默认的es-toolkit入口是两个不同的包路径。默认入口面向现代 API而compat入口专门用于兼容 Lodash 的调用方式keys只能从compat获取。本文后续所有示例均默认使用上述导入语句。三、基本用法普通对象、数组与字符串keys(object)返回对象自身的可枚举属性名数组。最简单的用法是传入一个普通对象import { keys } from es-toolkit/compat; // 普通对象的键 const object { a: 1, b: 2, c: 3 }; keys(object); // [a, b, c] // 数组的下标 const array [1, 2, 3]; keys(array); // [0, 1, 2] // 字符串的下标 keys(hello); // [0, 1, 2, 3, 4]几个值得注意的细节对数组而言返回的是字符串形式的索引0、1、2这与Object.keys的行为一致对字符串会先将其视为类数组对象返回每个字符的索引返回结果只包含自身属性不包含继承属性这一点在下一节展开。参数与返回值项目说明参数objectany类型要获取键的对象可为任意值包括数组、字符串、函数、null、undefined返回值string[]对象自身可枚举属性名的数组四、排除继承属性函数与构造函数场景keys只返回自身的可枚举属性从函数或构造函数原型链上继承下来的属性会被排除。官方文档给出了经典的构造函数示例import { keys } from es-toolkit/compat; function Foo() { this.a 1; this.b 2; } Foo.prototype.c 3; keys(new Foo()); // [a, b]c 是原型上的属性因此被排除这一行为与测试用例 src/compat/object/keys.spec.ts 完全一致测试中构造Foo.prototype.b 2最终断言keys(new Foo())只返回[a]。五、类数组对象的特殊处理与原生Object.keys不同keys对类数组对象有专门的逻辑分支包括 TypedArray、arguments对象、字符串对象等import { keys } from es-toolkit/compat; // TypedArray const typedArray new Uint8Array([1, 2, 3]); keys(typedArray); // [0, 1, 2] // arguments 对象 function example() { return keys(arguments); } example(a, b, c); // [0, 1, 2]从源码看src/compat/object/keys.tsarrayLikeKeys辅助函数会用times(object.length, ...)生成[0, 1, ..., length-1]索引序列并通过Set去重对 Buffer 特殊处理过滤掉offset和parent两个非索引属性兼容 Node.js 0.10 时代 Buffer 的行为对 TypedArray 特殊处理过滤掉buffer、byteLength、byteOffset三个非索引属性兼容 PhantomJS 2 的行为对数组直接返回「索引 剩余自身属性」对非数组类数组对象用Object.hasOwn再次校验索引是否真实存在。上述过滤逻辑在测试 src/compat/object/keys.spec.ts 中有明确验证// Buffer 不应包含 offset 或 parent 键 const buffer Buffer.from(test); keys(buffer); // [0, 1, 2, 3] // TypedArray 不应包含 buffer、byteLength、byteOffset 键 const typedArray new Uint8Array(1); keys(typedArray); // [0]此外源码还会把稀疏数组当作稠密数组处理[1, , 3]这类存在空洞的数组也会返回[0, 1, 2]见 测试用例并且数组上挂载的自定义属性同样会被纳入结果[0, a]见 测试用例。六、null 与 undefined 的安全处理keys对空值非常宽容传入null或undefined不会抛出异常而是安全返回空数组import { keys } from es-toolkit/compat; keys(null); // [] keys(undefined); // []在测试中src/compat/object/keys.spec.ts这一行为甚至在Object.prototype上挂载了额外属性时依然成立。对于字符串以外的原始值数字、布尔等keys会将其装箱为对象后再处理例如keys(0)返回[]、keys(a)返回[0]这也与 IE 9 时代的 Lodash 兼容测试保持一致见 测试用例。七、原型对象跳过constructor属性当传入的对象本身是一个原型对象如Foo.prototype时源码会额外过滤掉constructor键。这一判断依赖内部工具函数 isPrototypeexport function isPrototype(value: object) { const constructor value?.constructor; const prototype typeof constructor function ? constructor.prototype : Object.prototype; return value prototype; }即如果传入值恰好等于某个构造函数的prototype或等于Object.prototype就判定为原型对象随后在主函数中过滤掉constructor// 主函数中的关键分支src/compat/object/keys.ts#L31-L37 const result Object.keys(Object(object)); if (!isPrototype(object)) { return result; } return result.filter(key key ! constructor);对应的测试src/compat/object/keys.spec.ts验证了keys(Foo.prototype)返回[a]而不包含constructor同时keys({ constructor: Foo, a: 1 })也会排除constructor。八、源码级实现解析完整执行流程结合以上内容可以梳理出 keys 主函数 的完整执行流程keys(object) ├─ 1. isArrayLike(object) 为 true │ └─ 是 → 走 arrayLikeKeys 分支类数组专用逻辑 │ ├─ 生成 0..length-1 索引序列 │ ├─ Buffer → 过滤 offset/parent │ ├─ TypedArray → 过滤 buffer/byteLength/byteOffset │ ├─ 合并非索引自身属性 │ └─ 非数组时用 Object.hasOwn 校验索引 │ └─ 2. 否则 ├─ Object.keys(Object(object)) 取自身可枚举属性 └─ isPrototype(object) 为 true └─ 是 → 过滤掉 constructor └─ 否 → 直接返回可以看到keys相比Object.keys()多出的开销主要集中在类数组判定isArrayLike、索引序列生成与Set构建、Buffer/TypedArray 兼容分支、原型对象判定isPrototype以及最终的过滤操作。这正是官方文档提示「该函数运行较慢建议改用Object.keys()」的底层原因——这些兼容逻辑是有成本的普通对象场景下原生 API 完全没有这些负担。九、与keysIn的对比是否包含继承属性es-toolkit 兼容层还提供了keysIn函数src/compat/object/keysIn.ts它与keys的最大区别是keysIn会包含原型链上的可枚举继承属性而keys只返回自身属性。import { keysIn } from es-toolkit/compat; function Foo() {} Foo.prototype.a 1; console.log(keysIn(new Foo())); // [a]包含继承属性两者在类数组对象、Buffer、TypedArray、原型对象的处理策略上保持一致keysIn同样会过滤 Buffer 的offset/parent与 TypedArray 的buffer/byteLength/byteOffset同样跳过原型对象的constructor区别仅在于遍历范围keysIn使用for...in遍历会沿原型链向上keys则基于Object.keys只取自身属性。如果迁移自 Lodash 的_.keysIn请对应使用keysIn不要与keys混用。十、实战建议何时用keys何时用Object.keys综合官方文档的警告与源码分析可以给出如下选型建议场景推荐 API理由新代码、无 Lodash 迁移负担Object.keys()无兼容逻辑性能更好从 Lodash 迁移、追求行为完全一致keyses-toolkit/compat完整兼容类数组、原型对象、空值等边界行为需要包含继承属性keysInes-toolkit/compat对应 Lodash 的_.keysIn需要键值对数组toPairs/entries键值场景有更直接的 APIkeys的核心价值在于行为兼容性稀疏数组按稠密处理、字符串按索引展开、TypedArray/Buffer 过滤特殊属性、原型对象跳过constructor、空值安全返回[]——这些细节都是Object.keys()不具备或行为不同的地方。如果你的代码依赖这些 Lodash 语义keys就是迁移时的可靠替代否则请遵循官方建议直接使用原生Object.keys()。十一、进一步阅读函数实现src/compat/object/keys.ts测试用例完整覆盖边界行为src/compat/object/keys.spec.ts原型对象判定工具src/compat/_internal/isPrototype.ts包含继承属性的兄弟函数src/compat/object/keysIn.ts兼容层统一导出src/compat/compat.ts英文原版参考文档docs/compat/reference/object/keys.md【免费下载链接】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),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →