Lodash源码阅读-baseHasIn

Lodash 源码阅读-baseHasIn

概述

baseHasIn 是 Lodash 内部的一个小工具函数,它的工作很简单:判断一个对象里面有没有某个属性,不管是自己直接拥有的还是从"父辈"那里继承来的。它是公开 API _.hasIn 的内部实现,不支持多层路径查询(比如 "a.b.c"),只能查询直接属性。

前置学习

依赖知识

  • JavaScript 原型链:这是 JS 中继承的实现方式,子对象可以使用父对象的属性和方法
  • in 操作符 :JS 里的一个操作符,用来检查一个属性是否存在于对象或其原型链中,比如 'name' in person
  • Object 构造函数 :JS 内置的函数,可以把各种值包装成对象,比如 Object(123) 会返回一个数字对象

相关函数

  • baseHasbaseHasIn 的"堂兄弟",只查自己家的东西,不管继承来的
  • hasIn :基于 baseHasIn 实现的公共 API,支持多层路径查询
  • hasPath:专门处理多层属性路径的函数,比如查询 "user.profile.name"

源码实现

javascript 复制代码
/**
 * The base implementation of `_.hasIn` without support for deep paths.
 *
 * @private
 * @param {Object} [object] The object to query.
 * @param {Array|string} key The key to check.
 * @returns {boolean} Returns `true` if `key` exists, else `false`.
 */
function baseHasIn(object, key) {
  return object != null && key in Object(object);
}

实现思路

baseHasIn 的实现超级简单,仅仅一行代码,但这一行里面藏着三个关键点:

  1. 空值检查 :首先确保对象不是 nullundefined,防止程序崩溃。

  2. 包装成对象 :用 Object(object) 把任何值转成对象。这样即使你传入数字或字符串这样的基本类型,也能正常工作。

  3. 用 in 操作符 :使用 JS 的 in 操作符来查找,这个操作符会查找整个原型链。这就是为什么 baseHasIn 能找到继承的属性,而不仅仅是自己的属性。

这三点结合起来,让 baseHasIn 能够安全、正确地检查一个属性是否可以被对象访问到,无论这个属性是直接拥有的还是继承的。

源码解析

函数参数

javascript 复制代码
function baseHasIn(object, key) {

这个函数接收两个参数:

  • object:要查询的对象,可以是任何东西,甚至是数字或字符串
  • key:要检查的属性名,通常是字符串,比如 "name"、"age"

实现代码

javascript 复制代码
return object != null && key in Object(object);

这短短一行代码做了三件事:

  1. object != null:检查 object 是否有值(不是 null 也不是 undefined)。这用了一个小技巧:在 JS 中,null == undefinedtrue,所以这一个判断可以同时排除这两种空值。

    javascript 复制代码
    null == null; // true
    undefined == null; // true
    123 == null; // false
  2. Object(object):把输入值转换为对象。这个操作对不同类型的值有不同效果:

    • 如果已经是对象,保持不变
    • 如果是数字,变成 Number 对象
    • 如果是字符串,变成 String 对象
    • 如果是布尔值,变成 Boolean 对象
    javascript 复制代码
    Object(123); // Number {123}
    Object("hello"); // String {"hello"}
    Object(true); // Boolean {true}
    Object({ a: 1 }); // {a: 1} (不变)
  3. key in Object(object):使用 in 操作符检查属性。这个操作符会查找整个原型链,而不仅仅是对象自己的属性。

    javascript 复制代码
    "toString" in {}; // true,因为所有对象都从 Object.prototype 继承了 toString 方法
    "length" in []; // true,数组有 length 属性
    "length" in "hello"; // false,但 "length" in Object("hello") 是 true

baseHas 与 baseHasIn 对比

为了更好理解 baseHasIn,让我们把它和 baseHas 放在一起看:

javascript 复制代码
// baseHas 实现
function baseHas(object, key) {
  return object != null && hasOwnProperty.call(object, key);
}

// baseHasIn 实现
function baseHasIn(object, key) {
  return object != null && key in Object(object);
}

主要区别在于查找范围:

  • baseHas 使用 hasOwnProperty,只查找对象自己直接拥有的属性,就像只在你自己的口袋里找钥匙
  • baseHasIn 使用 in 操作符,查找对象及其原型链上的所有属性,相当于不仅查你自己的口袋,还翻遍全家人的口袋

举个例子:

javascript 复制代码
var obj = {};
"toString" in obj; // true (继承自 Object.prototype)
obj.hasOwnProperty("toString"); // false (不是自己的属性)

// 用 Lodash 函数
_.hasIn(obj, "toString"); // true (使用 baseHasIn)
_.has(obj, "toString"); // false (使用 baseHas)

总结

baseHasIn 虽然看起来简单(就一行代码!),但它却巧妙地结合了 JavaScript 的 in 操作符和 Object 构造函数,让我们能够安全、方便地检查对象的属性,无论是自己的还是继承的。

通过这个小小的函数,我们可以学到几个重要的编程技巧:

  1. 安全检查 :先检查 nullundefined,避免程序崩溃
  2. 类型转换 :使用 Object() 包装器统一处理不同类型的输入
  3. 原型链查找 :利用 in 操作符查找整个原型链,而不仅仅是对象自身

这些技巧不仅适用于属性检查,在很多其他场景中也非常有用。当我们需要处理不确定来源的数据、考虑继承关系,或者创建灵活的 API 时,hasIn 这样的工具函数就能派上大用场。

最后,虽然现代 JavaScript 引入了可选链操作符 ?. 和空值合并操作符 ??,但在处理继承属性和更复杂的场景时,hasIn 仍然有其独特的价值。

相关推荐
QQ1__8115175156 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态6 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子6 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室6 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI6 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing6 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者6 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册6 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李6 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢6 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web