JavaScript实用库:Lodash源码数组函数解析(六)first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable
本章的内容主要是:first、flatten、flattenDeep、flattenDepth、baseFlatten、isFlattenable
Lodash是一个非常好用方便的JavaScript的工具库,使得我们对数据处理能够更加得心应手
接下来我要对Lodash的源码进行剖析学习
每天几个小方法,跟着我一起来学lodash吧
1、_.first -> _.head(array)
根据lodash中文文档介绍,通过该方法可以获取到数组的第一个元素
可以看到啊,它有两个名词:first 和 head
我们来看它的例子:
例子也很通俗易懂啊,这里我就不多说了
接下来看源码:
function head(array) {
//数组不为空则输出数组第一个元素
return (array && array.length) ? array[0] : undefined;
}
module.exports = head;
还好,源码很简单
2、_.flatten(array)
根据中文文档介绍:减少一级array嵌套深度
看到这个我们就立马想起了扁平化数组核心函数:baseFlatten,可能源码中都是基于它来实现的
下面直接来看例子啊
就一个例子,还挺容易懂的,发现在数组内部少了一个嵌套
那么这是怎么来实现的呢?下面看源码:
function flatten(array) {
//获取数组的长度
var length = array == null ? 0 : array.length;
//数组长度为0输出空数组
//不为0则使用baseFlatten函数向下扁平化1层
return length ? baseFlatten(array, 1) : [];
}
module.exports = flatten;
源码不多,果然是基于baseFlatten来实现的
有了这个核心函数还是很容易实现这个功能的
3、_.flattenDeep(array)
根据中文文档介绍,该方法能够将数组化为一维数组,也就是说无论嵌套多少层都能化为一维数组
下面我们来看例子:
也是一个简简单单的例子,希望源码也那么简单
下面我们来看源码:
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0;
/**
* Recursively flattens `array`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to flatten.
* @returns {Array} Returns the new flattened array.
* @example
*
* _.flattenDeep([1, [2, [3, [4]], 5]]);
* // => [1, 2, 3, 4, 5]
*/
function flattenDeep(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, INFINITY) : [];
}
module.exports = flattenDeep;
它的实现与flatten明明一模一样,为什么能够化为一维数组呢,因为我们定义的变量INFINITY的值是 1 / 0,这个值位于baseFlatten函数的第二个参数位时意味着展开层数无限,所以能化为一维数组啦
4、_.flattenDepth(array, [depth=1])
这个方法和前面两个差不多,但是该方法的第二个参数是能够指定层级的,默认为0,当第二个值没有时,该方法就和flatten是一样的了
我们接下来看例子;
这个我也不多说了,还是挺容易理解的
接下来我们看源码是怎么实现的:
function flattenDepth(array, depth) {
//获取数组长度
var length = array == null ? 0 : array.length;
//数组长度为0则输出空数组
if (!length) {
return [];
}
//确定depth的值
//当depth的值没有定义时,赋值为1
//当有定义时赋值传入值的整数值
depth = depth === undefined ? 1 : toInteger(depth);
//扁平化数组
return baseFlatten(array, depth);
}
module.exports = flattenDepth;
该方法还是基于baseFlatten的扁平化方法
既然这样,我觉得有必要再提及一次这个核心函数
5、baseFlatten
因为中文文档没有介绍,所以我们只能直接看源码了
/**
* The base implementation of `flatten` with support for restricting flattening.
*
* @private
* @param {Array} array The array to flatten.
* @param {number} depth The maximum recursion depth.
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
* @param {Array} [result=[]] The initial result value.
* @returns {Array} Returns the new flattened array.
*/
//这个方法用于数组展开
//array需要展开操作的数组,depth需要展开的层数
//predicate用于判断值是否可展开
//isStrict标识用于判断是否约束值必须通过predicate方法的检查
function baseFlatten(array, depth, predicate, isStrict, result) {
predicate || (predicate = isFlattenable)//predicate每次循环都会调用,用来判断当前值是否是一个可展开的array-like对象
result || (result = [])
if (array == null) {//需要展开的数组是空,就返回空数组
return result
}
for (const value of array) {
if (depth > 0 && predicate(value)) {//如果展开层数大于0且当前循环值可展开
if (depth > 1) {//如果展开层数大于一层就继续递归调用,层数减一
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {//如果只展开一层,就展开后push到result里
result.push(...value)
}
} else if (!isStrict) {//如果没有传递isStrict标识,就直接将当前循环值push入结果数组
result[result.length] = value
}
}
return result
}
export default baseFlatten
实现过程还是稍微比较复杂的
既然到了这里,还有一个函数我觉得也可以一并说一下:isFlattenable
6、isFlattenable
很遗憾,文档里面也没有介绍
该方法的功能是:检查一个变量是否是一个可展开的对象或者数组
接下来我们看源码:
/** Built-in value reference. */
const spreadableSymbol = Symbol.isConcatSpreadable
/**
* Checks if `value` is a flattenable `arguments` object or array.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
*/
function isFlattenable(value) {
return Array.isArray(value) || isArguments(value) ||
!!(spreadableSymbol && value && value[spreadableSymbol])
//如果是数组,则可展开
//如果是arguments对象,则可展开
//如果当前环境含有Symbol对象,且此变量含有Symbol.isConcatSpreadable属性,Symbol.isConcatSpreadable用于改变array或者array-like对象使用concat时的默认行为
}
export default isFlattenable
如果可展开则输出true,反之false
今天就到这里了,明天继续