Lodash源码阅读-baseKeysIn

Lodash 源码阅读-baseKeysIn

功能概述

baseKeysIn 是 Lodash 中的一个内部工具函数,用于获取对象的所有可枚举属性名(包括自身和继承的属性)。它是 _.keysIn 方法的基础实现,能够处理各种类型的对象,并根据对象的类型采用不同的处理策略。

baseKeys(只返回对象自身属性)不同,baseKeysIn 会返回对象自身的可枚举属性以及从原型链继承的可枚举属性。

前置学习

依赖函数

  • isObject:检查值是否为对象类型
  • nativeKeysIn:通过 for...in 循环获取对象所有可枚举属性的工具函数
  • isPrototype:检查值是否为原型对象

技术知识

  • 可枚举属性:JavaScript 对象属性的可枚举性及其对遍历的影响
  • 原型链:JavaScript 的继承机制,以及如何访问原型链上的属性
  • for...in 循环:遍历对象所有可枚举属性(包括继承的)的 JavaScript 语法
  • constructor 属性:对象原型上的特殊属性,需要特殊处理
  • hasOwnProperty:区分对象自身属性和继承属性的方法

源码实现

javascript 复制代码
function baseKeysIn(object) {
  if (!isObject(object)) {
    return nativeKeysIn(object);
  }
  var isProto = isPrototype(object),
    result = [];

  for (var key in object) {
    if (
      !(key == "constructor" && (isProto || !hasOwnProperty.call(object, key)))
    ) {
      result.push(key);
    }
  }
  return result;
}

实现思路

baseKeysIn 函数的实现思路可以概括为:

  1. 检查输入值是否为对象类型

    • 如果不是对象,直接调用 nativeKeysIn 获取所有属性名
    • 这是一种优化,避免对非对象类型进行复杂处理
  2. 如果是对象,判断是否为原型对象

    • 记录这个信息,后续用于处理 constructor 属性
  3. 使用 for...in 循环遍历对象的所有可枚举属性(包括继承的)

    • 特殊处理 constructor 属性,避免在某些情况下返回它
    • 将符合条件的属性名添加到结果数组
  4. 返回包含所有收集到的属性名的数组

这种实现在保证获取完整属性的同时,处理了 constructor 属性的特殊情况,提高了函数的健壮性。

源码解析

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

非对象类型处理

javascript 复制代码
if (!isObject(object)) {
  return nativeKeysIn(object);
}
  • 使用 isObject 检查 object 是否为对象类型
  • 如果不是对象(如原始类型、null、undefined),直接调用 nativeKeysIn 函数
  • nativeKeysIn 会使用 for...in 循环获取所有可枚举属性名

示例:

javascript 复制代码
// 非对象类型的处理
console.log(_.keysIn("hello")); // ['0', '1', '2', '3', '4']
console.log(_.keysIn(42)); // []
console.log(_.keysIn(null)); // []

变量初始化

javascript 复制代码
var isProto = isPrototype(object),
  result = [];
  • 使用 isPrototype 检查 object 是否为原型对象,结果存储在 isProto 变量中
  • 创建一个空数组 result,用于存储收集到的属性名

示例:

javascript 复制代码
// 检查是否为原型对象
function Person() {}
const proto = Person.prototype;
console.log(isPrototype(proto)); // true

const obj = { a: 1 };
console.log(isPrototype(obj)); // false

属性遍历和过滤

javascript 复制代码
for (var key in object) {
  if (
    !(key == "constructor" && (isProto || !hasOwnProperty.call(object, key)))
  ) {
    result.push(key);
  }
}

这段代码是函数的核心,它做了以下工作:

  1. 使用 for...in 循环遍历对象的所有可枚举属性(包括继承的)
  2. 对每个属性名 key 进行条件检查,排除以下情况:
    • 属性名为 'constructor' 且满足以下条件之一:
      • object 是原型对象(isProto 为 true)
      • 或者 constructor 不是 object 的自身属性
  3. 将通过检查的属性名添加到 result 数组

这个条件设计得很巧妙,主要用于处理 constructor 属性的特殊情况:

  • 对于原型对象,避免返回 constructor 属性,因为它通常不是用户定义的数据属性
  • 对于普通对象,如果 constructor 是继承的而非自身属性,也避免返回它

示例:

javascript 复制代码
// constructor 属性的处理
function Person() {}
Person.prototype.sayHello = function () {};
// 原型对象上有 constructor 和 sayHello 属性
console.log(_.keysIn(Person.prototype)); // ['sayHello']  (constructor 被排除)

// 如果用户在原型上自定义了 constructor
Person.prototype.constructor = CustomConstructor;
console.log(_.keysIn(Person.prototype)); // ['sayHello', 'constructor']

返回结果

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

与 baseKeys 的对比

baseKeysInbaseKeys 函数的主要区别在于是否包含继承的属性:

javascript 复制代码
// baseKeys 只返回对象自身的可枚举属性
function baseKeys(object) {
  if (!isPrototype(object)) {
    return nativeKeys(object);
  }
  var result = [];
  for (var key in Object(object)) {
    if (hasOwnProperty.call(object, key) && key != "constructor") {
      result.push(key);
    }
  }
  return result;
}

主要区别:

  1. baseKeys 使用 hasOwnProperty 过滤出自身属性,而 baseKeysIn 不过滤继承属性
  2. baseKeys 总是排除 constructor 属性,而 baseKeysIn 只在特定情况下排除
  3. baseKeys 对非原型对象使用 nativeKeys(基于 Object.keys),而 baseKeysIn 对非对象使用 nativeKeysIn

总结

baseKeysIn 是 Lodash 中用于获取对象所有可枚举属性名(包括继承的)的核心实现函数。

相关推荐
爱泡脚的鸡腿10 分钟前
HTML CSS 第二次笔记
前端·css
灯火不休ᝰ26 分钟前
前端处理pdf文件流,展示pdf
前端·pdf
智践行28 分钟前
Trae开发实战之转盘小程序
前端·trae
最新资讯动态33 分钟前
DialogHub上线OpenHarmony开源社区,高效开发鸿蒙应用弹窗
前端
lvbb6643 分钟前
框架修改思路
前端·javascript·vue.js
qq_4560016544 分钟前
43、接口请求需要时间,导致页面初始加载时会出现空白,影响用户体验
javascript·vue.js·ux
树上有只程序猿1 小时前
Java程序员需要掌握的技术
前端
从零开始学安卓1 小时前
Kotlin(三) 协程
前端
try again!1 小时前
rollup.js 和 webpack
开发语言·javascript·webpack