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 仍然有其独特的价值。

相关推荐
智商不够_熬夜来凑13 分钟前
【Radio & Checkbox】
前端·javascript·vue.js
xiaofeichaichai21 分钟前
Diff 算法
前端·javascript
wgc2k30 分钟前
Nest.js 基础-8-Hello,NestJS
开发语言·javascript·ecmascript
Larcher33 分钟前
从 0 到 1:用 Bun + axios 快速搭建 LLM API 客户端
前端·javascript
子午36 分钟前
基于DeepSeek的酒店客房管理系统~Python+DeepSeek智能问答+Vue3+Web网站系统
开发语言·前端·python
bkspiderx37 分钟前
Boa Web服务器HTTPS支持的源码改造方案
服务器·前端·https·web服务器·boa·https支持
贺今宵43 分钟前
Vue 3 + Capacitor 使用jeep-sqlite,web端使用本地sqlite数据库
前端·数据库·vue.js·sqlite·web
taocarts_bidfans1 小时前
Google Indexing API 外贸独立站主动推送收录实战开发
前端·独立站·外贸独立站·taoify
lichenyang4531 小时前
鸿蒙 Stage 模型到底是什么?一篇讲清 Ability、EntryAbility 和入口文件为什么这么设计
前端
JSMSEMI111 小时前
JSM12N60C 600V N沟道增强型功率MOSFET
开发语言·javascript·ecmascript