关于javascript:lodashjs源码flatten

性能

调用形式

_.flatten(array)

缩小一级array嵌套深度

_.flatten([1,[2,3,]]) 

// =< [1,2,3]

数组内的成员如果是数组,那么就会被开展到,外部的元素成为上一级数组的元素。

这种的性能实现起来很简略,首先入参是一个数组,返回也是一个数组


function flatten(array){
   let result = []
   for(let i = 0; i< array.length; i++){

        if(Array.isArray(array[i])) {
            // 解决数组中的元素 ,push到result中
        }else {
            result.push(array[i])
        }
   }
   
   
   return result
}

lodash源码实现

function flatten(array) {
  var length = array == null ? 0 : array.length;
  return length ? baseFlatten(array, 1) : [];
}

通过源码,咱们能够很清晰的失去flatten办法的外围性能都是由baseFlatten实现的。

常常应用lodash的开发者会发现,flattenDeepflattenDepth中有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正是flatten**办法的外围实现。

探秘baseFlatten

function baseFlatten(array, depth, predicate, isStrict, result) {
  // predicate默认为isFlattenable, 传入的array如果是能够`flatten`化,返回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默认为isFlattenable, 传入的array如果是能够flatten化,返回true.

假设入参baseFlatten(array, 1)

接下来看具体的解决局部.抽离出代码

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
    }
  }

第一个判断条件

depth > 0 && predicate(value)

flatten来讲,depth = 1,当for...of迭代出的元素predicate(value)true

看一下默认的实现

function isFlattenable(value) {
  return Array.isArray(value) || isArguments(value) ||
    !!(value && value[spreadableSymbol])
}

lodash默认认为数组,arguments 和 value[spreadableSymbol]Flattenable的。

predicate也能够手动传入。

如果第一轮的遍历出的元素是一个数组。执行的是如下的代码。没什么好说的。

 result.push(...value)

当迭代出的不是Flattenable(或者说是predicate(value)为false),会执行如下代码

result[result.length] = value

接下来思考depth为2的时候是下边的逻辑是如何执行的。

假如此时的入参数遍历进去的value为 [‘a’,’b’,’c’].此时

 if (depth > 1) {
        baseFlatten(value, depth - 1, predicate, isStrict, result)
 } 

执行的就是baseFlatten(['a','b','c'],1,isFlattenable,undefined,[]).

实际上执行的是flatten(['a','b','c']).只不过传入了一个result来寄存解决后的后果。depath缩小当前,就不会再向下继续执行递归了。

即使是depth为3甚至更高的元素,也会通过递归,每一次递归的后果保留到result中,执行到最初,便是返回最初的后果。

总结

flatten,flattenDeep,flattenDepth等办法都是通过baseFlatten衍生进去的。

再理论开发中,咱们也要学习作者的思路去形象封装代码。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理