Lodash源码阅读-baseIteratee

Lodash 源码阅读-baseIteratee

概述

baseIteratee 是 Lodash 内部的核心工具函数,它的任务很简单:把各种类型的值转换成标准的迭代器函数。这个函数是 Lodash 中 mapfilterfind 等高阶函数的基础,让这些函数能接受多种形式的参数,大大提高了 API 的灵活性和易用性。

前置学习

依赖函数

  • isArray:判断一个值是否为数组
  • identity:返回原值的函数,即 value => value
  • baseMatches:创建一个函数,检查对象是否匹配指定的源对象属性
  • baseMatchesProperty:创建一个函数,检查对象的指定路径上的值是否匹配给定值
  • property:创建一个函数,返回对象指定路径上的属性值

技术知识

  • 高阶函数:接收或返回函数的函数
  • 函数式编程:使用函数作为主要构建块的编程思想
  • 类型检查:根据值的类型执行不同的逻辑
  • 短路优化:根据条件提前返回结果,避免不必要的计算
  • 策略模式:根据输入类型选择不同的处理策略

源码实现

javascript 复制代码
function baseIteratee(value) {
  // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
  // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
  if (typeof value == "function") {
    return value;
  }
  if (value == null) {
    return identity;
  }
  if (typeof value == "object") {
    return isArray(value)
      ? baseMatchesProperty(value[0], value[1])
      : baseMatches(value);
  }
  return property(value);
}

实现思路

baseIteratee 的核心思想是根据输入值的类型返回合适的迭代器函数:

  1. 如果输入是函数,直接返回这个函数,不做任何处理
  2. 如果输入是 nullundefined,返回 identity 函数(原样返回值)
  3. 如果输入是对象类型:
    • 若是数组(如 ['name', 'fred']),返回检查对象属性值的函数
    • 若是普通对象,返回检查对象属性匹配的函数
  4. 如果是其他类型(字符串、数字等),返回获取对象属性的函数

这种设计让 Lodash 的高阶函数非常灵活,可以接受各种形式的参数,使 API 更加简洁易用。

源码解析

函数类型处理

javascript 复制代码
if (typeof value == "function") {
  return value;
}

首先检查 value 是否为函数。如果是函数,直接返回它。

javascript 复制代码
// 使用函数作为迭代器
_.map([1, 2, 3], function (n) {
  return n * 2;
});
// => [2, 4, 6]

注释中提到了 Safari 9 的 JIT 编译器 bug,这就是为什么不把 typeof value 结果存在变量里,而是直接在条件判断中使用。

空值处理

javascript 复制代码
if (value == null) {
  return identity;
}

如果 valuenullundefined== 可以同时检查这两种情况),返回 identity 函数:

javascript 复制代码
function identity(value) {
  return value;
}

这样处理后,当传入 null 时,迭代器会返回集合中的每个元素本身:

javascript 复制代码
// 使用 null 作为迭代器
_.map([1, 2, 3], null);
// => [1, 2, 3]

对象类型处理

javascript 复制代码
if (typeof value == "object") {
  return isArray(value)
    ? baseMatchesProperty(value[0], value[1])
    : baseMatches(value);
}

如果 value 是对象类型,还要进一步区分:

  1. 如果是数组(用 isArray 判断),假设它的格式是 [path, srcValue],表示"检查对象在指定路径上的值是否等于 srcValue":
javascript 复制代码
// 查找 'user' 属性值为 'barney' 的用户
_.find(users, ["user", "barney"]);
// 等价于 _.find(users, function(o) { return o.user === 'barney'; });
  1. 如果是普通对象,返回 baseMatches(value) 创建的函数,用于检查对象是否包含与该对象匹配的属性:
javascript 复制代码
// 查找匹配指定属性的对象
_.find(users, { user: "barney", active: true });
// 等价于 _.find(users, function(o) { return o.user === 'barney' && o.active === true; });

其他类型处理

javascript 复制代码
return property(value);

如果 value 不是上述任何类型,就返回 property(value) 创建的函数,用于获取对象的属性值:

javascript 复制代码
// 提取所有用户的 'user' 属性
_.map(users, "user");
// 等价于 _.map(users, function(o) { return o.user; });

property 函数根据路径类型选择合适的实现:

javascript 复制代码
function property(path) {
  return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
}

总结

baseIteratee 是 Lodash 中一个巧妙设计的核心函数,它通过简单的类型检查,实现了强大的迭代器转换功能。它的特点包括:

  1. 接口统一:不管输入什么类型,总是返回一个函数,让高阶函数可以统一处理
  2. 灵活多变:支持函数、属性路径、对象匹配等多种方式创建迭代器
  3. 简单易用:将复杂的类型判断和转换逻辑封装起来,对外提供简洁的接口
  4. 可扩展性 :通过 _.iteratee 方法,允许用户定制迭代器的行为

这个函数虽然简短,但它大大增强了 Lodash API 的灵活性和易用性,是整个库的重要基石。通过学习它的设计,我们可以了解如何设计灵活而强大的函数式 API。

相关推荐
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_9:(信件语义标记)
前端·css·笔记·ui·html
前端老石人1 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang2 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
幼儿园技术家2 小时前
前端如何设计权限系统(RBAC / ABAC)?
前端
前端摸鱼匠3 小时前
Vue 3 的v-bind合并行为:讲解v-bind与普通属性合并的规则
前端·javascript·vue.js·前端框架·ecmascript
REDcker4 小时前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
donecoding5 小时前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马5 小时前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren5 小时前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川5 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端