Lodash 源码阅读-xor
概述
xor 是 Lodash 中用于计算多个数组的异或结果的函数。它创建一个新数组,这个数组中的元素只存在于传入数组的其中一个中,遵循严格比较。该函数实现了数学中的对称差集操作,返回的元素顺序是由第一次出现的顺序决定的。
前置学习
依赖函数
- baseXor:内部实现异或操作的核心函数,执行实际的对称差集计算
- baseRest:处理函数的剩余参数,实现类似 ES6 中的 rest 参数功能
- arrayFilter:过滤数组元素,根据传入的谓词函数移除不符合条件的元素
- isArrayLikeObject:检查值是否类似数组对象,确保传入 baseXor 的参数有效
技术知识
- 集合操作:理解数学中的对称差集概念,即只存在于一个集合中的元素组成的集合
- 函数式编程:部分应用和函数组合,将小型专用函数组合成复杂功能
- REST 参数:处理不定数量参数的技巧,使函数能接收任意数量的参数
源码实现
var xor = baseRest(function (arrays) {
return baseXor(arrayFilter(arrays, isArrayLikeObject));
});
实现思路
xor 函数的实现非常简洁,它基于以下思路:
- 使用
baseRest创建一个能处理不定数量参数的函数 - 过滤传入的参数,只保留类数组对象
- 将过滤后的数组传给
baseXor进行异或计算
这种设计利用了函数组合的思想,将具体的异或计算逻辑委托给 baseXor 函数,自身只负责参数处理和调用关系。整个函数结构清晰,职责单一,体现了良好的函数式编程设计原则。
源码解析
- 函数定义与参数收集
var xor = baseRest(function(arrays) {
首先使用 baseRest 创建一个新函数,这个函数能够接收任意数量的参数并将它们收集到 arrays 数组中。baseRest 是 Lodash 内部实现类似 ES6 中 ...rest 语法的函数。
示例调用:
xor([1, 2], [2, 3]); // arrays = [[1, 2], [2, 3]]
- 参数验证与过滤
return baseXor(arrayFilter(arrays, isArrayLikeObject));
对传入的 arrays 使用 arrayFilter 进行过滤,只保留那些满足 isArrayLikeObject 检查的值。这确保了传入 baseXor 的都是类数组对象,避免了处理非法参数。
示例:
xor([1, 2], "不是数组", null, [3, 4]);
// 过滤后只保留 [1, 2] 和 [3, 4]
- 异或计算与结果返回
最后一步是调用 baseXor 函数处理过滤后的数组,计算出所有数组的异或结果并返回。
isArrayLikeObject 会检查值是否为对象且具有类数组特性(有 length 属性且可索引)。这样可以接受真正的数组和类数组对象(如 arguments),但会排除字符串、函数等。
完整调用示例:
xor([2, 1], [2, 3]); // 返回 [1, 3]
// 1 只在第一个数组中出现
// 3 只在第二个数组中出现
// 2 在两个数组中都出现,被排除
总结
- 参数校验优先:在执行核心逻辑前先验证和过滤输入,提高函数的健壮性和抗错能力
- 函数组合设计:通过组合小型、单一职责的函数构建复杂功能,提高代码可维护性
- 职责分离原则:将参数处理与核心逻辑分离,使函数结构更清晰
- 防御性编程:通过类型检查防止非预期输入,避免运行时错误
在现代 JavaScript 中,可以使用 Set 结构结合 filter 和 some 方法实现类似功能,但 Lodash 的实现提供了更多的兼容性保障和边界情况处理。