Lodash 源码阅读-overRest
概述
overRest
是 Lodash 内部的工具函数,它模拟了 ES6 的剩余参数功能,能将函数参数分成固定参数和剩余参数两部分,并对剩余参数进行转换处理。这是实现 Lodash 柯里化和部分应用的核心基础。
前置学习
依赖函数
- nativeMax:原生 Math.max 的引用,获取两个数的最大值
- apply:封装了 Function.prototype.apply 的函数调用工具
技术知识
- 函数柯里化:将接收多个参数的函数转换为一系列接收单一参数的函数
- 剩余参数 :ES6 的
...args
语法的模拟实现 - arguments 对象:类数组对象,包含调用函数时传入的所有参数
- apply 方法:以指定的 this 值和参数数组调用函数
源码实现
js
function overRest(func, start, transform) {
start = nativeMax(start === undefined ? func.length - 1 : start, 0);
return function () {
var args = arguments,
index = -1,
length = nativeMax(args.length - start, 0),
array = Array(length);
while (++index < length) {
array[index] = args[start + index];
}
index = -1;
var otherArgs = Array(start + 1);
while (++index < start) {
otherArgs[index] = args[index];
}
otherArgs[start] = transform(array);
return apply(func, this, otherArgs);
};
}
实现思路
overRest
函数通过闭包实现参数的分割与转换:
- 确定分割位置:通过
start
参数决定哪些是固定参数,哪些是需要处理的剩余参数 - 收集和转换参数:将原始参数分为两组,对剩余参数应用转换函数
- 重组参数:将固定参数与转换后的剩余参数组合成新的参数数组
- 调用原函数:使用新的参数数组调用原始函数
源码解析
函数签名:
js
function overRest(func, start, transform)
func
: 需要处理的目标函数start
: 参数分割点的位置(默认为 func.length - 1)transform
: 用于处理剩余参数的转换函数
实现步骤解析:
-
确定分割位置:
jsstart = nativeMax(start === undefined ? func.length - 1 : start, 0);
这行代码确保
start
至少为 0,默认取函数的形参个数减 1。示例:如果
func
为function(a, b, c) {}
,则func.length
为 3,默认start
为 2。 -
创建闭包函数:返回一个新函数,用于处理参数:
jsreturn function () { // 函数实现 };
-
收集剩余参数:
jsvar args = arguments, index = -1, length = nativeMax(args.length - start, 0), array = Array(length); while (++index < length) { array[index] = args[start + index]; }
假设调用
function(1, 2, 3, 4, 5)
且start
为 2:args
为[1, 2, 3, 4, 5]
length
为5 - 2 = 3
array
最终为[3, 4, 5]
(剩余参数)
-
收集固定参数:
jsindex = -1; var otherArgs = Array(start + 1); while (++index < start) { otherArgs[index] = args[index]; }
接续上例:
otherArgs
初始为长度为 3 的数组- 循环后变为
[1, 2, undefined]
(固定参数)
-
应用转换与调用:
jsotherArgs[start] = transform(array); return apply(func, this, otherArgs);
- 如果
transform
是identity
(返回原值)函数,则otherArgs
变为[1, 2, [3, 4, 5]]
- 最终调用
func(1, 2, [3, 4, 5])
- 如果
总结
overRest
函数通过巧妙的参数处理机制,实现了以下几点技术亮点:
- 向后兼容性:在 ES6 之前的环境中模拟了剩余参数功能
- 参数转换灵活性 :通过
transform
参数提供了对剩余参数的自定义处理能力 - 函数式编程支持:为 Lodash 中的柯里化、偏函数应用等高阶函数提供了基础设施
从设计模式角度看,overRest
采用了函数式编程中的高阶函数模式,通过返回新函数的方式实现了对原函数的装饰和增强,体现了"不变性"和"组合性"的函数式编程理念。