前言
flattenDeep
是用于展平多维数组或内嵌数组的数组工具函数,lodash
实现这个简单的函数的时候,为了其复用代码而用了很多巧妙的思路,比如使用了 Infinity
的特性,使得 flattenDeep
、flatten
、union
等函数都可以共用一份代码
为了代码的健壮性,flattenDeep
会判断属性 Symbol.isConcateSpreadable
,这个属性控制对象是否可以被合并,即定义调用 concat()
函数时的行为,因此 flattenDeep
也可以对类数组对象使用
思路分析
源码分析
1. flattenDeep
- 传入参数分析
array
目标数组,被展平的数组或类数组对象
- 源码分析
传入数组,并传入 Infinity
作为展平层数
function flattenDeep(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, INFINITY) : [];
}
2. baseFlatten
- 传入参数分析
array
目标数组,被展平的数组或类数组对象depth
展平的层数,有多少层就会递归展平多少次predicate
判断是否可行,默认isFlattenable
,判断是否可展平isStrict
限制通过predicate
函数的值,准备以后说到union
函数时再详细分析result
递归结果,可以在多次递归中传递形成最终结果
- 源码分析
function baseFlatten(array, depth, predicate, isStrict, result) {
var index = -1,
length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
arrayPush(result, value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
初始化 index
和 length
,处理 value
的函数 predicate
默认是 isFlattenable
var index = -1,
length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
判断 value
是否符合要求,默认情况即 predicate
(默认 isFlattenable
) 返回值是否为 true
,判断是否可以展平,如果是数组、类数组对象 arguments
,或是有 Symbol.isConcatSpreadable
属性,就可以被展平
// ...
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
// ...
} else if (!isStrict) {
result[result.length] = value;
}
}
// ...
判断 depth
是否大于 1, 如果等于 1 则直接填入新数组,如果大于 1 则继续递归
// ...
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
arrayPush(result, value);
}
// ...
JS 中的 Infinity
flattenDeep
中借助了 Infinity
来完成无限循环,这里就展开说说 Infinity
的一些特性和作用
Inifity
代表了JS 中最大的数字值,在 JS 中用数字类型可以存储的最大值 2^1024
表示,其本身却大于 Number.MAX_VALUE
(用 1.79e+308
表示) 。
Infinity
和任何数字加减乘都会得到 Infinity,1/Inifnity
会得到 0
。
Infinity
之间的运算,加乘结果是 Infinity
,减除结果是 NaN
早期的 JS当中 Inifity
值是可以更改的,后来在 ES5 中更改为只读值。而 Infinity
还分为 Infinity
和 -Infinity
,一个是最大值一个是最小值。Infinity
值的作用是其作为最大数字和不会因加上数字变化,可以用来比较大小,无限次数的循环
Number.isFinite
和 isFinite
都可以可以用来判断是否是 Infinity
、-Infinity
、NaN
这三个无限值,区别在于 Number.isFinite
不会强制转换类型,即输入其他不会判断为 NaN
;isFinite
正好相反。
值得注意的是,ES2020 新特性 BigInt
类型因为没有位数限制的关系,因此不具有 Infinity
值,也不可以与其进行计算
通常可以用下面这几种办法来获取 Infinity
值
Number.POSITIVE_INFINITY
Infinity
1/0
2**1024
Math.pow(2, 1024)
总结
flattenDeep
利用 Infinity
无限递归,展平数组
Infinity
是 number
类型,因此 depth
参数不仅可以实现无限递归,还可以兼容传入固定的展平层数
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!