Lodash源码阅读-baseRest

Lodash 源码阅读-baseRest

概述

baseRest 是 Lodash 内部工具函数,用于模拟 ES6 的剩余参数功能。它通过组合 overRest 和 setToString 两个函数,创建一个能处理不定数量参数的新函数,并保留原函数的字符串表示。这在实现柯里化和函数部分应用中非常有用。

前置学习

依赖函数

  • overRest:处理剩余参数的核心函数
  • setToString:保持函数的 toString 方法,便于调试
  • identity :返回输入值本身的函数,即 x => x

源码实现

js 复制代码
function baseRest(func, start) {
  return setToString(overRest(func, start, identity), func + "");
}

实现思路

baseRest 函数虽然只有一行代码,但实现了两个关键功能:

  1. 使用 overRest 创建一个能处理剩余参数的新函数
  2. 使用 setToString 保留原函数的字符串表示

为什么这样做?因为在 JavaScript 中,函数的 toString() 方法会返回函数的源代码,这对调试和函数识别很有用。当使用高阶函数时,新函数默认的 toString() 不会反映原函数的信息,所以需要专门设置。

源码解析

函数签名:function baseRest(func, start)

  • func: 需要处理的原始函数
  • start: 从第几个参数开始算作"剩余参数"(索引从 0 开始)

实现解析:

js 复制代码
return setToString(overRest(func, start, identity), func + "");
  1. 使用 overRest 创建处理剩余参数的新函数
  2. 用 identity 保持剩余参数原样不变
  3. 用 setToString 保留原函数的字符串表示

参数处理核心原理

当使用 baseRest 创建的函数被调用时,参数处理过程如下:

js 复制代码
// 创建一个包装函数
const wrapper = baseRest(function (first, rest) {
  console.log(first); // 10
  console.log(rest); // [20, 30, 40]
  return first + rest.reduce((sum, n) => sum + n, 0);
}, 1);

// 调用包装函数
wrapper(10, 20, 30, 40); // 结果: 100

处理流程:

  1. 参数分割:

    • 固定参数:[10](索引 0 之前的参数)
    • 剩余参数:[20, 30, 40](索引 1 及之后的参数)
  2. 调用准备:

    • 对剩余参数应用 identity 函数(保持不变)
    • 形成调用数组 otherArgs = [10, [20, 30, 40]]
  3. 函数调用:

    • 通过 apply(func, this, otherArgs) 调用
    • 相当于 func(10, [20, 30, 40])
    • 形参 first 接收第一个参数 10
    • 形参 rest 接收第二个参数 [20, 30, 40]

应用场景示例

1. 求和函数

js 复制代码
const sum = baseRest(function (first, rest) {
  return rest.reduce((total, num) => total + num, first);
}, 1);

sum(10, 20, 30, 40); // => 100

2. 数据库查询构建器

js 复制代码
const query = baseRest(function (table, conditions) {
  return `SELECT * FROM ${table} WHERE ${conditions.join(" AND ")}`;
}, 1);

query("users", "age > 18", "status = 'active'");
// => "SELECT * FROM users WHERE age > 18 AND status = 'active'"

3. 事件处理器

js 复制代码
const createEventHandler = baseRest(function (eventName, listeners) {
  return function (data) {
    console.log(
      `事件「${eventName}」触发,共有 ${listeners.length} 个处理函数`
    );
    listeners.forEach((listener) => listener(data));
  };
}, 1);

const clickHandler = createEventHandler(
  "点击",
  (data) => console.log("处理器1:", data),
  (data) => console.log("处理器2:", data)
);

clickHandler({ x: 100, y: 200 });

总结

baseRest 主要解决两个问题:

  1. 参数处理:在 ES6 之前环境中模拟剩余参数功能
  2. 元数据保留:保持原函数的字符串表示

即使在现代 JavaScript 已有原生剩余参数的情况下,baseRest 在实现函数式编程模式、处理兼容性和创建高级函数工具时仍然非常有价值。

相关推荐
枣把儿9 分钟前
开源!全套公众号写作、封面、发布自动化工具包!
前端·命令行
志尊宝12 分钟前
AI原生前端开发(031):AI辅助的性能分析与瓶颈定位
javascript·人工智能·ai-native
陶醉的松鼠12 分钟前
前端容易忽略的 debugger 调试技巧
前端
我命由我1234513 分钟前
6-3.Python 异常处理 - 异常处理进阶(else 块与 finally 块、异常传递、自定义异常)
开发语言·前端·数据库·后端·python·学习·java-ee
龙九山17 分钟前
我的 10 个 npm 插件,差点被 AI 判了死刑
前端·开源
deli00719 分钟前
键盘按键测试:按下就点亮,keydown 延迟精确到 1 毫秒
前端
adinnet202620 分钟前
持续智能问数:多轮对话状态管理、下钻钻取与经营驾驶舱的演进
javascript·数据库·人工智能
FYKJ_201023 分钟前
springboot高考志愿填报推荐系统14332-计算机课程设计、毕业设计
javascript·spring boot·python·架构·django·课程设计·高考
Amos_Web26 分钟前
通过 Rspack 源码学 Rust(三):用 Default 与 std::mem::take 取出字段所有权
前端
全栈若城34 分钟前
从源码拆解一个 AIUI 每日一词智能体:页面、离线索引与硬件交互
javascript