lodash里的sumBy和meanBy

181 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情

使用说明

sumBy

lodash里的sumBy主要是以第二个参数为基准去求一组数组的总和,用法同maxBy和minBy相同。

var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
 
_.sumBy(objects, function(o) { return o.n; });
// => 20
 
// The `_.property` iteratee shorthand.
_.sumBy(objects, 'n');
// => 20

_.sumBy(objects);
// => '[object Object][object Object][object Object][object Object]'

_.sumBy();
// => 0

meanBy

lodash里的meanBy则是以第二个参数为基准求一组数组的平均值。

var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
 
_.meanBy(objects, function(o) { return o.n; });
// => 5
 
_.meanBy(objects, 'n');
// => 5

_.meanBy(objects);
// => NaN

_.meanBy()
// => NaN

源码实现

sumBy

在之前的篇章中,我们讲到实现maxBy和minBy的源码实现,在迭代遍历上均调用了名为baseIteratee的方法,baseIteratee方法主要处理第二个参数各种情况,并且转换为函数类型供遍历时调用。

在sumBy的源码实现中,迭代数据使用baseSum方法,对于第二个参数的处理同maxBy和minBy一样,仍然调用baseIteratee方法。

function sumBy(array, iteratee) {
  return (array && array.length)
    ? baseSum(array, baseIteratee(iteratee, 2))
    : 0;
}

sumBy源码里先判断源数据是否存在并且身上是否存在length方法,条件成立的话调用baseSum方法,否则返回0。

baseSum方法在sum实现方法中用到,主要是遍历数据、存储计算等处理。

function baseSum(array, iteratee) {
  var result,
      index = -1,
      length = array.length;

  while (++index < length) {
    var current = iteratee(array[index]);
    if (current !== undefined) {
      result = result === undefined ? current : (result + current);
    }
  }
  return result;
}

而不管是minBy和maxBy,又或者是sumBy以及后续讲解的meanBy,其中对于第二个参数的处理均是通过调用baseIteratee方法处理的,目的在于对第二个参数转换为函数形式供每一次遍历时调用。

function baseIteratee(value) {
  if (typeof value == 'function') {
    return value;
  }
  if (value == null) {
    return identity;
  }
  if (typeof value == 'object') {
    return isArray(value)
      ? baseMatchesProperty(value[0], value[1])
      : baseMatches(value);
  }
  return property(value);
}

meanBy

lodash里的meanBy,在实现上是直接调用封装的baseMean方法,baseMean主要用于mean方法的实现以及meanBy方法的实现。

function meanBy(array, iteratee) {
  return baseMean(array, baseIteratee(iteratee, 2));
}

调用baseIteratee则将meanBy的第二个参数进行类型判断处理,最终返回一个函数供遍历时调用。

而baseMean的实现依旧存在依托于baseSum方法。

function baseMean(array, iteratee) {
  var NAN = 0 / 0;
  var length = array == null ? 0 : array.length;
  return length ? (baseSum(array, iteratee) / length) : NAN;
}

小结

sumBy和meanBy在实现上大同小异,meanBy在内部依托于baseSum方法。

其中重点关注的应该是baseIteratee的实现,对于如何将第二个参数进行容错处理以及转换。因为无论时是maxBy、minBy、sumBy和meanBy,都借助该方法处理第二个参数,第二个参数都会被转换成函数供每次遍历时调用。

同时也应该去理解每次遍历赋值为什么不是直接赋值而是通过函数调用的形式。大多数方法的封装也并非是一开始就想到的,而是在找到通用性之后去重构的,而我们可以学习它重构的思路去琢磨实际项目中方法的拓展性。