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

相关推荐
yaoganjili1 分钟前
WebGL打开 3D 世界的大门(五):正射投影
前端·canvas·动效
寅时码2 分钟前
一个脚本让任何框架无痛实现 SSR,无需转到 Next.js、Nuxt.js
前端·node.js
见青..16 分钟前
【学习笔记】文件上传漏洞--二次渲染、.htaccess、变异免杀
前端·笔记·web安全·文件上传
北京_宏哥19 分钟前
🔥Jmeter(三) - 从入门到精通 - 测试计划(Test Plan)的元件(详解教程)
前端·jmeter·面试
一个西瓜大小33 分钟前
css单位
前端·css
Jasmin Tin Wei38 分钟前
蓝桥杯 web 新鲜的蔬菜(css3)
前端·蓝桥杯·css3
斯~内克1 小时前
前端单页应用性能优化全指南:从加载提速到极致体验
前端·性能优化
dododododoooo1 小时前
python处理两份经纬度数据的对应关系
前端·windows·python
人总该做点什么1 小时前
聊聊 CSS
前端·css
明天好,会的1 小时前
极简设计的力量:用 `apiStore` 提升项目效率与稳定性
前端·javascript·vue.js