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 .