Lodash 源码阅读-concat
概述
concat
是 Lodash 的一个数组函数,用来合并数组。它的作用很简单:把一个数组和其他数组或值连接起来,生成一个新数组。这个函数模仿了 JavaScript 原生的 Array.prototype.concat()
,但做了一些优化,让使用更方便。
前置学习
依赖函数
- arrayPush:把一个数组的内容添加到另一个数组末尾
- baseFlatten:把嵌套数组展平到指定深度
- copyArray:复制一个数组的内容到新数组
- isArray:检查一个值是否为数组
技术知识
- arguments 对象:函数内部用来获取所有参数的特殊对象
- 浅拷贝:复制对象的直接引用,而不是深层内容
- 条件判断:根据不同情况执行不同代码
- 循环 :使用
while
循环遍历参数
源码实现
javascript
/**
* Creates a new array concatenating `array` with any additional arrays
* and/or values.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Array
* @param {Array} array The array to concatenate.
* @param {...*} [values] The values to concatenate.
* @returns {Array} Returns the new concatenated array.
* @example
*
* var array = [1];
* var other = _.concat(array, 2, [3], [[4]]);
*
* console.log(other);
* // => [1, 2, 3, [4]]
*
* console.log(array);
* // => [1]
*/
function concat() {
var length = arguments.length;
if (!length) {
return [];
}
var args = Array(length - 1),
array = arguments[0],
index = length;
while (index--) {
args[index - 1] = arguments[index];
}
return arrayPush(
isArray(array) ? copyArray(array) : [array],
baseFlatten(args, 1)
);
}
实现思路
concat
函数的实现思路很直接:
- 检查是否有参数,没有就返回空数组
- 第一个参数当作基础数组
- 把剩余参数收集起来
- 基础数组是真数组就复制一份,不是就把它包装成数组
- 对剩余参数进行一级扁平化处理
- 把扁平化后的参数追加到基础数组的副本中
- 返回最终合并的结果
这样既保证了原数组不变,又能正确处理各种类型的参数(数组、单个值等)。
源码解析
参数检查
javascript
var length = arguments.length;
if (!length) {
return [];
}
这段先检查传入的参数数量。如果没有参数(length
为 0),就直接返回空数组 []
。这是防错处理,确保函数不会出错。
参数处理
javascript
var args = Array(length - 1),
array = arguments[0],
index = length;
while (index--) {
args[index - 1] = arguments[index];
}
这段代码做了三件事:
- 创建一个新数组
args
用来存放除第一个参数外的所有参数 - 把第一个参数存为
array
变量 - 用
while
循环从后往前,把第二个到最后一个参数收集到args
数组中
为什么从后往前循环?这样写比较简洁,可以减少一个循环变量。
数组合并
javascript
return arrayPush(
isArray(array) ? copyArray(array) : [array],
baseFlatten(args, 1)
);
这段代码是核心:
- 先看
array
是不是数组- 是数组:复制一份,防止修改原数组
- 不是数组:包装成数组,如
3
变成[3]
- 对剩余参数
args
进行一级扁平化,比如[[1], 2]
变成[1, 2]
- 用
arrayPush
把扁平化的结果添加到处理过的基础数组中 - 返回最终结果
"一级扁平化"是什么意思?就是只展开一层嵌套,比如:
[1, [2, [3]]]
会变成[1, 2, [3]]
- 里面的
[3]
不会再被展开
总结
concat
函数虽然简单,但体现了几个重要的编程思想:
-
不修改原数据
- 通过复制原数组来保证原数据不变
- 这种做法让函数更安全,减少意外错误
-
灵活处理不同类型
- 支持数组、单个值、混合类型作为参数
- 通过类型检查和适当转换,让 API 使用更方便
-
一致的行为
- 行为与原生
Array.prototype.concat
保持一致 - 一级扁平化,不会过度展开嵌套数组
- 行为与原生
-
组合式实现
- 通过组合多个小函数完成功能
- 每个函数专注做好一件事,代码更清晰易维护