性能
调用形式
_.flatten(array)
缩小一级 array 嵌套深度
_.flatten([1,[2,3,]])
// =< [1,2,3]
数组内的成员如果是数组,那么就会被开展到,外部的元素成为上一级数组的元素。
这种的性能实现起来很简略,首先入参是一个数组,返回也是一个数组
function flatten(array){let result = []
for(let i = 0; i< array.length; i++){if(Array.isArray(array[i])) {// 解决数组中的元素,push 到 result 中}else {result.push(array[i])
}
}
return result
}
lodash 源码实现
function flatten(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, 1) : [];}
通过源码,咱们能够很清晰的失去 flatten
办法的外围性能都是由 baseFlatten
实现的。
常常应用 lodash
的开发者会发现,flattenDeep
和 flattenDepth
中有baseFlatten
function flattenDepth(array, depth) {
const length = array == null ? 0 : array.length
if (!length) {return []
}
depth = depth === undefined ? 1 : +depth
return baseFlatten(array, depth)
}
function flattenDeep(array) {
const length = array == null ? 0 : array.length
return length ? baseFlatten(array, INFINITY) : []}
baseFlatten
正是 flatten**
办法的外围实现。
探秘 baseFlatten
function baseFlatten(array, depth, predicate, isStrict, result) {
// predicate 默认为 isFlattenable, 传入的 array 如果是能够 `flatten` 化,返回 true,predicate || (predicate = isFlattenable)
result || (result = [])
if (array == null) {return result}
for (const value of array) {if (depth > 0 && predicate(value)) {if (depth > 1) {// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {result.push(...value)
}
} else if (!isStrict) {result[result.length] = value
}
}
return result
}
predicate
默认为 isFlattenable
, 传入的 array 如果是能够flatten
化,返回true
.
假设入参baseFlatten(array, 1)
。
接下来看具体的解决局部. 抽离出代码
for (const value of array) {if (depth > 0 && predicate(value)) {if (depth > 1) {baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {result.push(...value)
}
} else if (!isStrict) {result[result.length] = value
}
}
第一个判断条件
depth > 0 && predicate(value)
对 flatten
来讲,depth = 1
,当 for...of
迭代出的元素 predicate(value)
为true。
看一下默认的实现
function isFlattenable(value) {return Array.isArray(value) || isArguments(value) ||
!!(value && value[spreadableSymbol])
}
lodash
默认认为 数组,arguments 和 value[spreadableSymbol]
是 Flattenable
的。
predicate
也能够手动传入。
如果第一轮的遍历出的元素是一个数组。执行的是如下的代码。没什么好说的。
result.push(...value)
当迭代出的不是 Flattenable
(或者说是predicate(value)
为 false),会执行如下代码
result[result.length] = value
接下来思考 depth 为 2 的时候是下边的逻辑是如何执行的。
假如此时的入参数遍历进去的 value 为 [‘a’,’b’,’c’]. 此时
if (depth > 1) {baseFlatten(value, depth - 1, predicate, isStrict, result)
}
执行的就是baseFlatten(['a','b','c'],1,isFlattenable,undefined,[])
.
实际上执行的是 flatten(['a','b','c'])
. 只不过传入了一个result
来寄存解决后的后果。depath
缩小当前,就不会再向下继续执行递归了。
即使是 depth
为 3 甚至更高的元素,也会通过递归,每一次递归的后果保留到 result
中,执行到最初,便是返回最初的后果。
总结
flatten
,flattenDeep
,flattenDepth
等办法都是通过 baseFlatten
衍生进去的。
再理论开发中,咱们也要学习作者的思路去形象封装代码。