美文网首页
Underscore源码阅读:flatten

Underscore源码阅读:flatten

作者: San十二 | 来源:发表于2018-11-10 17:26 被阅读0次

    flatten

    flatten是用来实现数组扁平化的,并加入了shallow函数strict来表示是否只将数组进行一次扁平化和是否对参数有严格要求。

    然而我觉得官方的实现在效率上是有问题的。忽略shallowstrict,单看flatten本身的实现。

    var flatten = function (input, shallow, strict, startIndex) {
      var output = [],
        idx = 0;
      for (var i = startIndex || 0, length = input && input.length; i < length; i++) {
        var value = input[i];
        if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
          //flatten current level of array or arguments object
          if (!shallow) value = flatten(value, shallow, strict);
          var j = 0,
            len = value.length;
          output.length += len;
          while (j < len) {
            output[idx++] = value[j++];
          }
        } else if (!strict) {
          output[idx++] = value;
        }
      }
      return output;
    };
    

    underscore源码的实现中,对于嵌套数组中的元素,会进入下一层flatten函数调用;在这层调用中,所有数组会被推入output并返回上一层(output[idx++] = value;);返回上一层后,又会遍历一遍这个数组(while (j < len) output[idx++] = value[j++])。

    也就是说,这相当于将嵌套数组中的元素遍历了两遍。

    然而这种遍历两次并不是不能避免的。

    // 忽略startIndex的实现
    var flatten = function (input, shallow) {
      var res = [];
      (function fn(res, array, deep) {
        array.forEach(item => {
          if (isArrayLike(item) && (_.isArray(item) || _.isArguments(item))) {
            if (shallow && deep) {
              res.push(item);
            } else {
              fn(res, item, true);
            }
          } else {
            res.push(item);
          }
        });
      })(res, input, false);
      return res;
    }
    

    我们将最终返回结果的引用res在整个flatten调用栈中都调用,凡是遇见非数组元素,就将这个元素pushres中;遇到数组,也只是进入下一层调用中,将所有非数组元素推进去。这样就可以避免非数组元素被遍历两次了。

    2018.11.27更新:
    Underscore源码没有问题……今早睡醒突然在想flatten函数,发现我的遍历是不能满足strict参数的……源码应该是为了满足strict参数所以才遍历了两遍,没毛病。

    相关文章

      网友评论

          本文标题:Underscore源码阅读:flatten

          本文链接:https://www.haomeiwen.com/subject/fmazxqtx.html