New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lodash源码研析-数组合久必分chunk #3

Open
littlewin-wang opened this Issue Apr 16, 2018 · 0 comments

Comments

1 participant
@littlewin-wang
Copy link
Owner

littlewin-wang commented Apr 16, 2018

引言

lodash 是前端常用工具库,其源码具有很高的参考价值。
本文是 lodash 源码研析的开篇之作,之后将按照 API 依次遍历整个 lodash 框架。
对于内部调用的函数,会在第一次引用到时进行细读。

话说天下大势,分久必合,合久必分。

作用

chunk() 函数用来将数组进行一级升维,刚好是数组扁平化的逆向操作。
数组升维分块的重要性在于它可以将多个项目的处理在执行队列上分开,在每个项目处理之后,给予其他事件机会运行,这样就可能避免长时间占据队列导致的体验差,出错等。
试用于大量的 DOM 操作,事件处理队列等。

依赖

  • 可遍历对象的检测函数
    注意检测 array-like 对象的方法,是对象不是数组,但是有 length 属性,且属性值为非负 Number 类型即可。
// 是否是一个遍历方法的参数,也就是需要和Array.map的参数一样,第一个是值,第二个是索引,第三个是对象本身
function isIterateeCall(value, index, object) {
  // 首先判断是否为对象
  if (!isObject(object)) {
    return false;
  }

  // 考虑index的为数字或者字符形式 (1 or '1')
  var type = typeof index;
  if (type == 'number'
        ? (isArrayLike(object) && isIndex(index, object.length))
        : (type == 'string' && index in object)
      ) {
    return eq(object[index], value);
  }
  return false;
}
  • lodash 自创切割函数
    lodash 中引用 ES6 的 功能不多,很多基础方法都自行实现。
function baseSlice(array, start, end) {
  var index = -1,
      length = array.length;

  if (start < 0) {
    start = -start > length ? 0 : (length + start);
  }
  end = end > length ? length : end;
  if (end < 0) {
    end += length;
  }
  length = start > end ? 0 : ((end - start) >>> 0);
  start >>>= 0;

  var result = Array(length);
  while (++index < length) {
    result[index] = array[index + start];
  }
  return result;
}

源码

**
 * Creates an array of elements split into groups the length of `size`.
 * If `array` can't be split evenly, the final chunk will be the remaining
 * elements.
 *
 * @static
 * @memberOf _
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to process.
 * @param {number} [size=1] The length of each chunk
 * @param- {Object} [guard] 可迭代对象, 用来检测是否和前两个参数满足可遍历对象的条件
 * @returns {Array} Returns the new array of chunks.
 * @example
 *
 * _.chunk(['a', 'b', 'c', 'd'], 2);
 * // => [['a', 'b'], ['c', 'd']]
 *
 * _.chunk(['a', 'b', 'c', 'd'], 3);
 * // => [['a', 'b', 'c'], ['d']]
 */

function chunk(array, size, guard) {
  // 这个 guard 参数如果和前两个参数满足可遍历对象的条件,就将size强制为1
  // 为什么要这么做,没搞懂??
  if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
    size = 1;
  } else {
    size = nativeMax(toInteger(size), 0);
  }
  var length = array == null ? 0 : array.length;
  if (!length || size < 1) {
    return [];
  }
  var index = 0,
      resIndex = 0,
      result = Array(nativeCeil(length / size));

  while (index < length) {
    // 用自制刀 baseSlice 去切割数组 array
    result[resIndex++] = baseSlice(array, index, (index += size));
  }
  return result;
}

module.exports = chunk;

总结

  • chunk 函数实现易于理解,但基本上大半的代码都在处理条件判断、检查参数等事情。
  • lodash 试图将函数做的更加通范,满足更多应用场景。
  • lodash 自创了很多基础工具、内部函数。

引用

本文使用「 署名 4.0 国际」创作共享协议。
本文同步发布于Littlewin's Blog,欢迎多多交流。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment