本篇分析下flatten
家族的方法,包括flatten
、flattenDeep
、flattenDepth
、flatMap
、flatMapDeep
、flatMapDepth
,最重要的是他们的核心方法baseFlatten
。最后给出几个方法的原生实现。
核心方法 baseFlatten
六个flatten
方法全都是封装的baseFlatten
方法,这个方法主要是有四个比较特殊的参数:
depth
是扁平化的深度,也就是扁平化递归流程执行几次,在结果的体现上就是array
的内部嵌套要解开几层。
predicate
是断言函数,目的是判断要不要对某元素
执行扁平化。
isStrict
是如何处理断言函数判断为假
的元素,isStrict
为真的话就直接抛弃该元素,为假就保留该元素
result
是初始的结果数组,默认为空数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import isFlattenable from './isFlattenable.js';
function baseFlatten(array, depth, predicate, isStrict, result) { predicate || (predicate = isFlattenable); result || (result = []);
if (array == null) { return result; }
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; } } return result; }
export default baseFlatten;
|
flatten 家族
flatten
flatten
方法是执行的depth
为1
的baseFlatten
方法,也就是说执行一次扁平化处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import baseFlatten from './.internal/baseFlatten.js';
function flatten(array) { const length = array == null ? 0 : array.length; return length ? baseFlatten(array, 1) : []; }
export default flatten;
|
flattenDeep
flattenDeep
方法是执行的depth
为无限大
的baseFlatten
方法,也就是说执行扁平化处理一直到底,把所有的嵌套全都展平。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import baseFlatten from './.internal/baseFlatten.js';
const INFINITY = 1 / 0;
function flattenDeep(array) { const length = array == null ? 0 : array.length; return length ? baseFlatten(array, INFINITY) : []; }
export default flattenDeep;
|
flattenDepth
flattenDeep
方法是执行的depth
为给定值
的baseFlatten
方法,也就是说执行扁平化固定次数,对数组的嵌套进行了固定深度的展平。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import baseFlatten from './.internal/baseFlatten.js';
function flattenDepth(array, depth) { const length = array == null ? 0 : array.length; if (!length) { return []; } depth = depth === undefined ? 1 : +depth; return baseFlatten(array, depth); }
export default flattenDepth;
|
flatMap
flatMap
和flatten
的区别是flatMap
方法要先执行map
,使用iteratee
将每个元素进行处理后,再进行扁平化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import baseFlatten from './.internal/baseFlatten.js'; import map from './map.js';
function flatMap(collection, iteratee) { return baseFlatten(map(collection, iteratee), 1); }
export default flatMap;
|
flatMapDeep
详见flattenDeep
和flatMap
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import baseFlatten from './.internal/baseFlatten.js'; import map from './map.js';
const INFINITY = 1 / 0;
function flatMapDeep(collection, iteratee) { return baseFlatten(map(collection, iteratee), INFINITY); }
export default flatMapDeep;
|
flatMapDepth
详见flattenDepth
和flatMap
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import baseFlatten from './.internal/baseFlatten.js'; import map from './map.js';
function flatMapDepth(collection, iteratee, depth) { depth = depth === undefined ? 1 : +depth; return baseFlatten(map(collection, iteratee), depth); }
export default flatMapDepth;
|
原生写法
最新的规范和实现,已经支持了原生扁平化处理。
Array.prototype.flat()
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let arr1 = [1, 2, [3, 4]]; arr1.flat();
let arr2 = [1, 2, [3, 4, [5, 6]]]; arr2.flat();
let arr3 = [1, 2, [3, 4, [5, 6]]]; arr3.flat(2);
let arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]; arr4.flat(Infinity);
|
Array.prototype.flatMap()
flatMap() 方法首先使用map
函数映射每个元素,然后将结果扁平化成一个新数组。它与 map
连着深度值为 1 的 flat
几乎相同,但 flatMap
通常在合并成一种方法的效率稍微高一些。
1 2 3 4 5 6 7 8 9 10 11
| let arr1 = [1, 2, 3, 4];
arr1.map((x) => [x * 2]);
arr1.flatMap((x) => [x * 2]);
arr1.flatMap((x) => [[x * 2]]);
|
flatMapDeep
原生的 flatMap 只能展开一层,下面利用原生方法实现完全扁平化,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const flatMapDeep = (arr, iteratee) => { return arr.flatMap((subArray, index, array) => { subArray = iteratee != null ? iteratee(subArray, index, array) : subArray; return Array.isArray(subArray) ? flatMapDeep(subArray, null) : subArray; }); };
flatMapDeep([1, [[2], [3, [4]], 5]]);
flatMapDeep([1, 2, 3], (x) => [[x, x]]);
|