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 中用于获取对象所有可枚举属性名(包括继承的)的核心实现函数。

相关推荐
程序员Bears几秒前
从零打造个人博客静态页面与TodoList应用:前端开发实战指南
java·javascript·css·html5
清风细雨_林木木40 分钟前
Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践
前端·css·vue.js
逊嘘44 分钟前
【Web前端开发】CSS基础
前端·css
小宁爱Python44 分钟前
深入掌握CSS Flex布局:从原理到实战
前端·javascript·css
Attacking-Coder1 小时前
前端面试宝典---webpack面试题
前端·面试·webpack
极小狐1 小时前
极狐GitLab 容器镜像仓库功能介绍
java·前端·数据库·npm·gitlab
程序猿阿伟2 小时前
《Flutter社交应用暗黑奥秘:模式适配与色彩的艺术》
前端·flutter
rafael(一只小鱼)2 小时前
黑马点评实战笔记
前端·firefox
weifont2 小时前
React中的useSyncExternalStore使用
前端·javascript·react.js
初遇你时动了情2 小时前
js fetch流式请求 AI动态生成文本,实现逐字生成渲染效果
前端·javascript·react.js