Lodash源码解析 Part1:Array、Collection

Lodash源码解析 Part1:Array、Collection

lodash究竟做了什么?

  • 封装

    封装可能会用到但是原生方法未提供的方法。
    每当想要处理一个数组对象,但是原生方法没有,去lodash里总能找到。

  • 容错

    类型判断,边界值等等

  • 性能

    http://jsben.ch/browse

遍历

结论:几乎全部是while……

举个例子

  function arrayMap(array, iteratee) {
    var index = -1,
        length = array == null ? 0 : array.length,
        result = Array(length);

    while (++index < length) {
      result[index] = iteratee(array[index], index, array);
    }
    return result;
  }
  • find,filter,slice,indexOf,forEach,filter,map,reduce等等,都是用while实现的

  • 多个数组间的并集交集差集等等,都是通过嵌套while实现的,并没有什么特别

  • 如果嵌套while,需要时使用continue label

All the results clearly shows that for loop are more proficient than for each than map/reduce/filter/find.
Map/Reduce/Filter/Find are slow because of many reason, some of them are

They have a call back to execute so that act as a overhead .
There are lot of corner cases that javascript function consider like getters, sparse array and checking arguments that are passed is array or not which adds up to overhead.

Note: If you’re using loops, always use them idiomatically since compilers are now smart enough to correctly optimize idiomatic loops
这句就像是看《正则表达式》,讲坑和避坑指南优化的时候,基本没有明确答案。原因是说,引擎一直在优化。

https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7
https://github.com/dg92/Performance-Analysis-JS

  • join,reverse 原生方法

  • string 的indexOf还是用的indexOf

排序

Array:sortedIndex

二分查找

Collection:sort

while配合原生sort

稳定排序

原生sort(就地算法)非稳定,意即,equal的数据顺序不能保持不变。

https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.sort

同mdn,对多个排序规则的例子,先.map处理好,并且记录index(以此保持稳定排序)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

     * @returns {number} Returns the sort order indicator for `object`.
     */
    function compareMultiple(object, other, orders) {
      var index = -1,
          objCriteria = object.criteria,
          othCriteria = other.criteria,
          length = objCriteria.length,
          ordersLength = orders.length;

      while (++index < length) {
        var result = compareAscending(objCriteria[index], othCriteria[index]);
        if (result) {
          if (index >= ordersLength) {
            return result;
          }
          var order = orders[index];
          return result * (order == 'desc' ? -1 : 1);
        }
      }
      // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
      // that causes it, under certain circumstances, to provide the same value for
      // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
      // for more details.
      //
      // This also ensures a stable sort in V8 and other engines.
      // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
      return object.index - other.index;
    }

中文Mdn说现在是稳定的,在chrome测试确实是稳定的了

https://www.baidu.com/link?url=-Oh5B3APlWXYOgF3rpSIe5LBBbYYcL6n38MrOXfOVG1FHm_mFx4V3KUPDYWoqobOQ-BiJ_wgu3Y4ZoCM337edMJF9EoAwM5DR-AN-00luAFrNuW6KZhTfchSjKYbAcQ5ito9duaYnyI6vGVfVEwL4K&wd=&eqid=dad841cd00041613000000035cb8f5aa
https://blog.csdn.net/qq_18145031/article/details/82500177
https://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms

Set And Get

Array() vs new Array()

and vs []

    result = Array(5)
    result[0]=1;
    result[1]=2;

vs

    result = [];
    result.push(1)
    result.push(2)

https://stackoverflow.com/questions/8205691/array-vs-new-array

还引发了 https://stackoverflow.com/questions/383402/is-javascripts-new-keyword-considered-harmful 这种讨论

官方说法:When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.

https://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-array-constructor

https://www.ecma-international.org/ecma-262/5.1/#sec-15.4.1

direct assign vs push

array[length+0]=value vs array.push(value)

lodash的例子

function arrayPush(array, values) {
    var index = -1,
        length = values.length,
        offset = array.length;

    while (++index < length) {
      array[offset + index] = values[index];
    }
    return array;
  }
  

http://jsben.ch/XOq7U 例子 assign direct faster than push

https://stackoverflow.com/questions/614126/why-is-array-push-sometimes-faster-than-arrayn-value 10年前……

https://stackoverflow.com/questions/42884123/appending-an-element-to-an-array-differences-between-direct-assignment-and-pus 2年前:push is doing a lot more work than assignment

https://stackoverflow.com/questions/559844/whats-better-to-use-in-php-array-value-or-array-pusharray-value

  • 数组长度确定的时候,用assign direct

  • 在数组长度未知的情况,有的时候用assign direct,有的时候会用push,I don't know why……

    两个例子

    function remove(array, predicate) {
      var result = [];
      if (!(array && array.length)) {
        return result;
      }
      var index = -1,
          indexes = [],
          length = array.length;
    
      predicate = getIteratee(predicate, 3);
      while (++index < length) {
        var value = array[index];
        if (predicate(value, index, array)) {
          result.push(value);
          indexes.push(index);
        }
      }
      basePullAt(array, indexes);
      return result;
    }
    
    function baseSortedUniq(array, iteratee) {
      var index = -1,
          length = array.length,
          resIndex = 0,
          result = [];
    
      while (++index < length) {
        var value = array[index],
            computed = iteratee ? iteratee(value) : value;
    
        if (!index || !eq(computed, seen)) {
          var seen = computed;
          result[resIndex++] = value === 0 ? 0 : value;//这个又是为什么? = value ===0 ? 0 : value 不就是相当于 = value;
        }
      }
      return result;
    }
    

类型

    this.__data__ = {
        'hash': new Hash,
        'map': new (Map || ListCache),
        'string': new Hash
      };

      ……

      function getMapData(map, key) {
      var data = map.__data__;
      return isKeyable(key)
        ? data[typeof key == 'string' ? 'string' : 'hash']
        : data.map;
    }

数组和数组用Hash
其他用Map

其他收获

  • result || (result = []) vs result = result ||[]

    减少一次没有必要的赋值

  • >>> vs /

    >>>0

    无符号右移,左边用0填充,永远非负:取整

    >>>1

    相当于/2,但做了取整、非负。在数组index的时候常用

  • concat(origin,...source)

    先将source concat成一个数组,然后再跟origin concat

    不会更占内存么?

你可能感兴趣的:(Lodash源码解析 Part1:Array、Collection)