最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • lodash 源码解析 -- flattenDeep

    正文概述 掘金(zer0fire)   2021-03-19   720

    前言

    flattenDeep 是用于展平多维数组或内嵌数组的数组工具函数,lodash 实现这个简单的函数的时候,为了其复用代码而用了很多巧妙的思路,比如使用了 Infinity 的特性,使得 flattenDeepflattenunion 等函数都可以共用一份代码

    为了代码的健壮性,flattenDeep 会判断属性 Symbol.isConcateSpreadable ,这个属性控制对象是否可以被合并,即定义调用 concat() 函数时的行为,因此 flattenDeep 也可以对类数组对象使用

    思路分析

    lodash 源码解析 -- flattenDeep

    源码分析

    1. flattenDeep

    1. 传入参数分析
    • array 目标数组,被展平的数组或类数组对象
    1. 源码分析

    传入数组,并传入 Infinity 作为展平层数

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

    2. baseFlatten

    1. 传入参数分析
    • array 目标数组,被展平的数组或类数组对象
    • depth 展平的层数,有多少层就会递归展平多少次
    • predicate 判断是否可行,默认 isFlattenable,判断是否可展平
    • isStrict 限制通过 predicate 函数的值,准备以后说到 union 函数时再详细分析
    • result 递归结果,可以在多次递归中传递形成最终结果
    1. 源码分析
    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;
    }
    

    初始化 indexlength,处理 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 表示) 。

    lodash 源码解析 -- flattenDeep

    Infinity 和任何数字加减乘都会得到 Infinity,1/Inifnity 会得到 0

    lodash 源码解析 -- flattenDeep

    Infinity 之间的运算,加乘结果是 Infinity,减除结果是 NaN

    lodash 源码解析 -- flattenDeep

    早期的 JS当中 Inifity 值是可以更改的,后来在 ES5 中更改为只读值。而 Infinity 还分为 Infinity-Infinity,一个是最大值一个是最小值。Infinity 值的作用是其作为最大数字和不会因加上数字变化,可以用来比较大小,无限次数的循环

    Number.isFiniteisFinite 都可以可以用来判断是否是 Infinity-InfinityNaN 这三个无限值,区别在于 Number.isFinite 不会强制转换类型,即输入其他不会判断为 NaNisFinite 正好相反。

    lodash 源码解析 -- flattenDeep

    值得注意的是,ES2020 新特性 BigInt 类型因为没有位数限制的关系,因此不具有 Infinity 值,也不可以与其进行计算

    通常可以用下面这几种办法来获取 Infinity

    Number.POSITIVE_INFINITY
    Infinity
    1/0
    2**1024
    Math.pow(2, 1024)
    

    总结

    flattenDeep 利用 Infinity 无限递归,展平数组

    Infinitynumber 类型,因此 depth 参数不仅可以实现无限递归,还可以兼容传入固定的展平层数


    起源地 » lodash 源码解析 -- flattenDeep

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元