news 2026/9/16 15:28:58

es-toolkit 兼容层 keysIn 详解:获取含继承属性的全部枚举键名

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
es-toolkit 兼容层 keysIn 详解:获取含继承属性的全部枚举键名

es-toolkit 兼容层 keysIn 详解:获取含继承属性的全部枚举键名

【免费下载链接】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

keysIn是 es-toolkit 兼容层(es-toolkit/compat)为对齐 lodash 而提供的对象工具函数,它返回对象自身与原型链上所有可枚举属性名的字符串数组。本文将以 keysIn 兼容文档 为骨架,结合 keysIn 源码 与其 完整测试用例,讲解该函数的基本用法、对数组 / 类数组 / 继承属性 / 空值的特殊处理,以及其底层实现原理与性能注意事项,帮助你在迁移 lodash 代码或日常取键场景中做出正确选择。

功能概览:keysIn 解决什么问题

keysIn的作用是:返回一个对象的所有可枚举属性名(包括自身属性与继承属性)组成的字符串数组

const allKeys = keysIn(object);

它与keys的核心区别在于:keys(见 keys 源码)只返回自身可枚举属性,而keysIn会沿着原型链一路向上,把继承到的可枚举属性也一并纳入结果。这与 lodash 的_.keysIn行为保持一致,方便 lodash 老项目平滑迁移。

注意:该函数仅返回字符串键的属性名(Symbol 键不在其中),且与 lodash 相同,结果数组不保证键的迭代顺序。

基本用法

es-toolkit/compat入口下导入即可使用:

import { keysIn } from 'es-toolkit/compat'; // 基本对象的键 const object = { a: 1, b: 2 }; keysIn(object); // => ['a', 'b'] // 数组的索引 const array = [1, 2, 3]; keysIn(array); // => ['0', '1', '2'] // 字符串的索引 keysIn('hello'); // => ['0', '1', '2', '3', '4']

值得注意的两个细节:

  • 数组返回的是字符串形式的索引'0'、'1'、'2',而不是数字下标;
  • 字符串原语会被自动装箱为 String 对象,从而返回字符位置索引。这一点在 keysIn.spec.ts 中有专门用例验证,且字符串对象上自定义的属性(如Object('a').a = 1)也会被返回。

参数与返回值

  • 参数objectany):要获取键的对象。
  • 返回值string[]):包含自身与继承的所有可枚举属性名(字符串键)的数组。

继承属性:与 keys 的本质差异

keysIn会包含原型链上可枚举的继承属性,这是它区别于keys的最关键行为:

import { keysIn } from 'es-toolkit/compat'; function Foo() { this.a = 1; this.b = 2; } Foo.prototype.c = 3; keysIn(new Foo()); // => ['a', 'b', 'c'](包含原型属性 'c') // constructor 会被排除 class MyClass { constructor() { this.prop = 1; } method() {} } MyClass.prototype.inherited = 2; keysIn(new MyClass()); // => ['prop', 'method', 'inherited'](constructor 被排除)

两个要点需要特别说明:

  1. 原型上的普通属性会被包含Foo.prototype.c = 3后,实例new Foo()的键自然多出'c'
  2. constructor被排除:当传入的对象本身是一个原型对象(prototype)时,结果中不会出现constructor。测试用例 keysIn.spec.ts 覆盖了多种原型场景,包括Foo.prototype、显式赋值{ constructor: Foo, a: 1 },以及伪造的Fake.prototype,验证constructor的过滤逻辑仅在原型对象上生效。

这一"排除 constructor"的行为并非在普通对象上硬性过滤,而是由源码中的isPrototype判定触发(见下文源码剖析)。

类数组对象的特殊处理

keysIn对类数组(array-like)对象走专门的分支逻辑,与普通对象不同:

import { keysIn } from 'es-toolkit/compat'; // TypedArray const typedArray = new Uint8Array([1, 2, 3]); keysIn(typedArray); // => ['0', '1', '2'](buffer、byteLength 等被排除) // arguments 对象 function example() { return keysIn(arguments); } example('a', 'b', 'c'); // => ['0', '1', '2']

行为细节包括:

  • TypedArray:会剔除bufferbyteLengthbyteOffset这些"非索引"的枚举属性(对应测试 keysIn.spec.ts);
  • arguments 对象:返回['0', '1', '2'],若在 arguments 上添加自定义属性a,结果会变为['0', '1', '2', 'a'](见 keysIn.spec.ts);
  • 稀疏数组按稠密处理const arr = [1]; arr[2] = 3;会返回['0', '1', '2'],缺失的下标也被补齐(keysIn.spec.ts);
  • 类数组对象保留 length{ 0: 'a', length: 1 }返回['0', 'length'](keysIn.spec.ts);
  • Buffer:不会返回offsetparent(keysIn.spec.ts);
  • 数组上的自定义属性也会保留[1].a = 1返回['0', 'a'],且Array.prototype.a = 1这类继承属性同样会被包含(keysIn.spec.ts)。

null / undefined 的安全处理

与 lodash 一致,keysIn对空值不会抛错,而是返回空数组:

import { keysIn } from 'es-toolkit/compat'; keysIn(null); // => [] keysIn(undefined); // => []

测试 keysIn.spec.ts 还额外验证了:即使此时在Object.prototype上挂载了属性(模拟污染环境),keysIn(null)keysIn(undefined)以及无参调用依然稳定返回[],不会受原型污染干扰。

源码实现剖析

从 keysIn 源码 可以看到,keysIn采用按类型分流的策略实现:

export function keysIn(object?: any): string[] { if (object == null) { return []; } switch (typeof object) { case 'object': case 'function': { if (isArrayLike(object)) { return arrayLikeKeysIn(object); } if (isPrototype(object)) { return prototypeKeysIn(object); } return keysInImpl(object); } default: { return keysInImpl(Object(object)); } } }

核心路径可拆解为四层:

  1. 空值短路object == null直接返回[]
  2. 类数组分支:通过 isArrayLike(基于length是否为合法长度且非函数)判定后进入arrayLikeKeysIn
  3. 原型对象分支:通过 isPrototype(比对value是否等于其constructor.prototype)判定后进入prototypeKeysIn,过滤掉constructor键;
  4. 默认分支keysInImpl直接使用for...in循环收集所有可枚举键(含继承),而对原始类型(数字、字符串、布尔、Symbol、BigInt)则先执行Object(object)装箱转换。

arrayLikeKeysIn(keysIn.ts)内部,先用times生成全部下标字符串,再用Set建立"应排除的键集合"(对 Buffer 额外加入offsetparent,对 TypedArray 额外加入bufferbyteLengthbyteOffset),随后通过for...in收集继承键并去重,最后按"是否为真数组"决定是否用Object.hasOwn过滤缺失下标。整个设计目标是在 lodash 兼容语义(稠密化、排除内建非索引属性、含继承键)与可读性之间取得平衡

性能注意事项:何时不该用它

官方文档在函数开头就给出了明确的警告——建议优先使用for...in循环或Object.keys()

keysIn由于包含类数组处理、原型链遍历等复杂逻辑,运行速度较慢。请改用更快的现代写法:for...in循环,或按需使用Object.keys()

在 keysIn 源码 中可以看到,keysInImpl本质上就是for...in,但外层还叠加了isArrayLikeisPrototypeisTypedArrayisBuffer等多重判定,以及下标数组生成与Set去重,这些都会带来额外开销。因此在追求性能的热路径代码中:

  • 只需自身键 → 用Object.keys(obj)
  • 需要含继承的可枚举键 → 直接写for (const key in obj)循环。

keysIn更适合用于与 lodash 逐字节对齐的兼容场景,或需要其类数组特殊语义(如 TypedArray 排除buffer等)的场合。

与相关函数的关系

在 es-toolkit 兼容层中,keysIn与以下函数构成一个"取键/取值"家族,可组合使用:

  • keys:只返回自身可枚举键(见 keys 文档 与 keys 源码),内部同样复用了arrayLikeKeysisPrototype逻辑,区别仅在于继承属性的取舍;
  • valuesIn:返回含继承属性的所有可枚举值(valuesIn.ts);
  • toPairsIn:返回含继承属性的[key, value]键值对数组(toPairsIn.ts);
  • assignIn/assignInWith:合并对象时同样遍历含继承的可枚举属性(assignIn.ts);
  • pickBy/omit/omitBy:在过滤属性时也会用到含继承键的遍历逻辑(pickBy.ts)。

这些函数共同构成了"全量遍历属性(own + inherited)"的兼容语义族。当你在迁移 lodash 代码时发现_.keysIn_.valuesIn_.toPairsIn等成对出现,可以直接用 es-toolkit 的对应函数无缝替换。

小结

keysIn是 es-toolkit 兼容层中语义最"宽"的取键函数:它返回自身 + 原型链上的全部可枚举字符串键,对数组、字符串、arguments、TypedArray 等类数组输入做专门的稠密化与属性过滤处理,对null/undefined返回空数组,并对原型对象排除constructor。其源码通过"空值短路 → 类数组分支 → 原型分支 → 默认for...in"的四级分流,在 lodash 兼容行为与现代实现之间做了清晰切分。日常开发中,除非需要与 lodash 行为严格对齐或依赖其类数组特殊语义,否则更推荐直接使用for...inObject.keys()以获取更好的性能。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 15:28:32

NFT数字藏品交易平台部署实战:Vue与ThinkPHP的Nginx伪静态配置

简介:一套可运营的NFT元宇宙数字藏品艺术品交易平台完整源码,前端Vue、后端ThinkPHP,适合快速搭建数字藏品发布与交易网站的开发者或企业。压缩包共1433个文件、约47.59MB,涵盖393个png图片素材、252个php业务逻辑、237个js脚本、…

作者头像 李华
网站建设 2026/9/16 15:28:26

FckSignups用户脚本实战:自动移除网站强制注册弹窗与登录遮罩

FckSignups,光看名字就带着一股子暴躁老哥的味道。我最早是在某个开发者吐槽帖里瞥见这个词的,顺手搜了一下,才发现它指向的是一类专门对付“强制注册”的实用型脚本项目。这类工具的核心诉求很简单,就是帮你把那些明明可以直接访…

作者头像 李华
网站建设 2026/9/16 15:27:23

MATLAB实现CLAHE算法:从原理到代码的完整指南

简介:在图像增强与预处理任务中,普通直方图均衡化常带来噪声放大与细节丢失的困扰,这使得对比度受限自适应直方图均衡化(CLAHE)成为更优选择。这套基于MATLAB实现的CLAHE算法源码,面向图像处理学习者、研究…

作者头像 李华
网站建设 2026/9/16 15:26:17

Flutter Windows视频渲染:Texture纹理机制与工程实践

简介:面向需要在Windows桌面端实现视频渲染的Flutter开发者,这是一份基于Texture机制、结合FFmpeg与Win32窗口的完整插件示例工程,填补了Windows平台相关中文资料稀缺的空白。代码包共297个文件,压缩后22.17MB,以C头文…

作者头像 李华