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。

相关推荐
李鸿耀1 分钟前
Flex布局完全指南,Flexbox 在线演示工具推送
前端·flexbox
涵信10 分钟前
第八节:React HooksReact 18+新特性-React Server Components (RSC) 工作原理
前端·react.js·前端框架
林十一npc42 分钟前
【Web功能测试】Web商城搜索模块测试用例设计深度解析
前端·测试用例·web测试·搜索框·商城测试
小p44 分钟前
迈向全栈:服务器上的软件安装
前端·后端
凯哥19701 小时前
Sciter.js 新手指南-GUI开发中的窗口使用指南
前端
Nuyoah.1 小时前
《vue3学习手记3》
前端·javascript·vue.js·学习·前端框架
最新资讯动态1 小时前
首发即燃!《群星纪元》携手鲸鸿动能引领科幻热潮,打造爆款国产SLG手游
前端
涵信1 小时前
第五节:React Hooks进阶篇-如何用useMemo/useCallback优化性能
前端·javascript·react.js
初遇你时动了情1 小时前
vue3 uniapp vite 配置之定义指令
javascript·vue.js·uni-app
BillKu1 小时前
reactive 解构赋值给 ref
前端·javascript·vue.js