function
Call mode
_.flatten(array)
Cut down one level array Nesting depth
_.flatten([1,[2,3,]])
// =< [1,2,3]
If the member of an array is an array , Then it will be expanded to , The inner element becomes the element of the upper array .
This function is very simple to implement , First, the input parameter is an array , Return is also an array
function flatten(array){
let result = []
for(let i = 0; i< array.length; i++){
if(Array.isArray(array[i])) {
// Processing elements in an array ,push To result in
}else {
result.push(array[i])
}
}
return result
}
lodash The source code to achieve
function flatten(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, 1) : [];
}
Through source , We can clearly get flatten The core function of the method is made up of baseFlatten Realized .
Regular use lodash The developers will find that ,flattenDeep and flattenDepth There is 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 It is flatten** The core implementation of the method .
explore a mystery baseFlatten
function baseFlatten(array, depth, predicate, isStrict, result) {
// predicate The default is isFlattenable, Incoming array If you can `flatten` turn , return 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 The default is isFlattenable, Incoming array If you can flatten turn , return true.
Let's assume that the input parameter is baseFlatten(array, 1).
Now let's look at the specific processing part . Pull out the code
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
}
}
The first condition is
depth > 0 && predicate(value)
Yes flatten Speaking of ,depth = 1, When for...of Iterated elements predicate(value) by true.
Take a look at the default implementation
function isFlattenable(value) {
return Array.isArray(value) || isArguments(value) ||
!!(value && value[spreadableSymbol])
}
lodash The default is Array ,arguments and value[spreadableSymbol] yes Flattenable Of .
predicate You can also manually pass in .
If the first round of traversal elements is an array . The following code is executed . There's nothing to say .
result.push(...value)
When the iteration is not Flattenable( Or rather, predicate(value) by false), Will execute the following code
result[result.length] = value
Next think depth by 2 It's how the logic below is executed .
Suppose that the input parameter at this time traverses out value by ['a','b','c']. here
if (depth > 1) {
baseFlatten(value, depth - 1, predicate, isStrict, result)
}
What we're doing is baseFlatten(['a','b','c'],1,isFlattenable,undefined,[]).
It's actually executing flatten(['a','b','c']). It's just that a result To store the processed results .depath After reduction , You don't have to go down the recursion .
even depth by 3 Even higher elements , It's also recursive , The result of each recursion is saved to result in , Carry it out to the end , Is to return to the final result .
summary
flatten,flattenDeep,flattenDepth And so on, through baseFlatten derived .
In actual development , We also need to learn from the author's ideas to abstract and encapsulate code .


