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

相关推荐
xjt_090111 分钟前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农22 分钟前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳1 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_2 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝2 小时前
RBAC前端架构-01:项目初始化
前端·架构
程序员agions2 小时前
2026年,微前端终于“死“了
前端·状态模式
万岳科技系统开发2 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法