Lodash源码阅读-nativeKeysIn

Lodash 源码阅读-nativeKeysIn

功能概述

nativeKeysIn 是 Lodash 中的一个内部工具函数,用于获取对象的所有可枚举属性名(包括自身和继承的属性)。它是 _.keysIn 方法的基础实现之一,通过原生的 for...in 循环遍历对象的所有可枚举属性,包括从原型链继承的属性。

与 nativeKeys(基于 Object.keys 实现)不同,nativeKeysIn 采用了更简单直接的方式,直接利用 JavaScript 的 for...in 循环来获取对象的所有可枚举属性,无论是自身的还是继承的。

前置学习

依赖函数

虽然 nativeKeysIn 本身没有直接依赖其他函数,但理解以下函数有助于更全面地理解它在 Lodash 中的定位:

  • baseKeysIn:获取对象所有可枚举属性名的基础实现,会根据对象类型调用 nativeKeysIn
  • keysIn:对外暴露的 API,用于获取对象自身和继承的可枚举属性名

内部调用链:keysIn → baseKeysIn → nativeKeysIn

技术知识

  • for...in 循环:JavaScript 中用于遍历对象所有可枚举属性(包括继承属性)的循环结构
  • 可枚举属性 :JavaScript 对象属性的一个特性,决定属性是否会出现在 for...in 循环中
  • 原型链:JavaScript 对象继承机制的基础,理解原型链对于理解属性继承至关重要
  • Object 构造函数:用于将原始值转换为对象,确保安全地访问属性

源码实现

javascript 复制代码
function nativeKeysIn(object) {
  var result = [];
  if (object != null) {
    for (var key in Object(object)) {
      result.push(key);
    }
  }
  return result;
}

实现思路

nativeKeysIn 函数的实现思路非常直接:

  1. 创建一个空数组,用于存储属性名
  2. 判断输入对象是否为 null 或 undefined,如果是则直接返回空数组
  3. 使用 for...in 循环遍历对象的所有可枚举属性(包括继承的)
  4. 将每个属性名添加到结果数组中
  5. 返回最终的属性名数组

这种实现方式利用了 JavaScript 的 for...in 循环特性,该循环会遍历对象自身的可枚举属性以及从原型链继承的可枚举属性,完美符合 keysIn 方法的需求。

源码解析

让我们逐行分析 nativeKeysIn 函数的实现:

函数签名和结果初始化

javascript 复制代码
function nativeKeysIn(object) {
  var result = [];
  • 函数接收一个参数 object,可以是任何类型的值
  • 创建一个空数组 result,用于存储属性名

空值处理

javascript 复制代码
if (object != null) {
  • 使用宽松比较 != 检查 object 是否为 null 或 undefined
  • 这是一种安全防护措施,确保不会在 null 或 undefined 上调用 for...in 循环

属性遍历和收集

javascript 复制代码
for (var key in Object(object)) {
  result.push(key);
}
  • Object(object) 将输入转换为对象类型,这是一种防御性编程的做法:
    • 如果 object 已经是对象,保持不变
    • 如果 object 是原始类型(如字符串、数字、布尔值),将其包装为对应的对象类型
    • 如果 object 是 null 或 undefined(虽然已经在前面检查过),则返回空对象 {}
  • for...in 循环遍历对象的所有可枚举属性,包括自身的和继承的
  • 每个属性名通过 push 方法添加到 result 数组中

返回结果

javascript 复制代码
  }
  return result;
}
  • 返回包含所有收集到的属性名的数组

应用场景

nativeKeysIn 函数主要通过 baseKeysIn 和 keysIn 函数被应用,适用于需要考虑继承属性的场景:

1. 获取对象所有属性(包括继承的)

javascript 复制代码
function Foo() {
  this.a = 1;
  this.b = 2;
}
Foo.prototype.c = 3;

const foo = new Foo();
console.log(_.keysIn(foo)); // ['a', 'b', 'c']

内部调用链:keysIn → baseKeysIn → nativeKeysIn

注意事项

使用 nativeKeysIn(通过 keysIn)时需要注意以下几点:

  1. 性能考虑:遍历所有继承属性可能会比仅遍历自身属性慢,特别是对于原型链较长的对象

  2. 非可枚举属性 :nativeKeysIn 只返回可枚举属性,非可枚举属性不会被收集

  3. 符号属性 :Symbol 类型的属性会被忽略,因为 for...in 循环不会遍历 Symbol 属性

  4. 属性排序:不同 JavaScript 引擎可能会以不同顺序遍历属性,不要依赖属性的顺序

  5. 原型污染 :如果原型链被恶意修改(原型污染),nativeKeysIn 可能会返回意外的属性

与 baseKeys 和 nativeKeys 的比较

为了更好地理解 nativeKeysIn,让我们将它与相关函数进行比较:

函数 获取自身属性 获取继承属性 实现方式 使用场景
nativeKeys ✅ ❌ 包装 Object.keys 仅需要获取自身属性的场景
baseKeys ✅ ❌ 使用 nativeKeys 或手动实现 处理普通对象和原型对象
nativeKeysIn ✅ ✅ 使用 for...in 循环 需要获取所有属性的场景
baseKeysIn ✅ ✅ 使用 nativeKeysIn 或手动实现 处理不同类型的对象

总结

nativeKeysIn 函数是 Lodash 中的一个简单而强大的工具函数,用于获取对象的所有可枚举属性名,包括从原型链继承的属性。它的主要特点包括:

  1. 简单性 :直接利用 JavaScript 的 for...in 循环,实现简洁明了
  2. 完整性:返回对象的所有可枚举属性,包括继承的属性
  3. 安全性 :通过 Object() 和 null 检查,确保处理各种输入类型
  4. 实用性:在需要处理继承属性的场景中非常有用,如对象合并、深度克隆等
相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄4 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95274 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大4 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师4 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端