Lodash 源码阅读-apply
概述
apply
是 Lodash 内部的一个函数,它对原生的 Function.prototype.apply
方法进行了封装和优化。这个函数通过根据参数数量选择不同的调用方式,来提高函数调用的性能。
前置学习
依赖函数
apply
函数非常独立,没有依赖其他 Lodash 函数。
技术知识
- 函数调用方式:JavaScript 中
call
和apply
的区别和使用场景 - 参数数组:如何处理和传递参数数组
- 性能优化:通过条件判断减少函数调用开销的技巧
- switch 语句:JavaScript 中 switch 的使用方式
源码实现
function apply(func, thisArg, args) {
switch (args.length) {
case 0:
return func.call(thisArg);
case 1:
return func.call(thisArg, args[0]);
case 2:
return func.call(thisArg, args[0], args[1]);
case 3:
return func.call(thisArg, args[0], args[1], args[2]);
}
return func.apply(thisArg, args);
}
实现思路
apply
函数的实现非常巧妙,它根据传入参数数组的长度,采用不同的调用策略:
- 检查参数数组
args
的长度 - 如果参数数量是 0 到 3 个,就直接使用
func.call
,并明确列出每个参数 - 如果参数数量超过 3 个,则使用
func.apply
传递完整的参数数组 - 所有情况下都返回函数调用的结果
这种实现方式避免了 apply
在处理小参数量时的性能损失,因为 call
比 apply
在少量参数时性能更好。
源码解析
判断参数长度
switch (
args.length
// 各种情况...
) {
}
这段代码使用 switch
语句根据参数数组的长度来选择不同的处理方式。这是一种明确而高效的条件分支处理方式。
少量参数优化
case 0: return func.call(thisArg);
case 1: return func.call(thisArg, args[0]);
case 2: return func.call(thisArg, args[0], args[1]);
case 3: return func.call(thisArg, args[0], args[1], args[2]);
这部分代码展示了优化的核心:
- 当参数数量较少(0-3 个)时,直接使用
call
方法 - 明确列出每个参数,避免了数组参数的解析开销
- 每个分支直接返回函数调用的结果
例如,对于只有一个参数的情况:
func.call(thisArg, args[0]); // 比 func.apply(thisArg, args) 更高效
默认情况处理
return func.apply(thisArg, args);
当参数数量超过 3 个时,使用传统的 apply
方法。在这种情况下,apply
方法的性能优势开始显现,因为它可以直接接收参数数组。
`
总结
Lodash 的 apply
函数虽然简短,但却体现了几个重要的编程原则:
-
性能优化:根据不同的参数数量选择最高效的函数调用方式,这是一种微优化,在大量调用时能带来显著的性能提升
-
API 设计:保持与原生
apply
相同的接口,使得函数可以无缝替代原生方法 -
代码简洁:通过
switch
语句清晰地表达了不同情况的处理逻辑,没有复杂的条件嵌套 -
默认情况处理:对于不在优化范围内的情况,退回到标准方法,保证了函数的通用性
这种优化方式也提醒我们,在 JavaScript 中,有时候直接使用 call
并明确列出参数,比使用 apply
和参数数组更高效,特别是在参数数量较少的情况下。