JavaScript实用库:Lodash源码数组函数解析(五)fill、baseFill、findIndex、baseFindIndex、baseIteratee、findLastIndex

本章的内容主要是:fill、isIterateeCall、baseFill、findIndex、baseFindIndex、baseIteratee、findLastIndex


在这里插入图片描述

Lodash是一个非常好用方便的JavaScript的工具库,使得我们对数据处理能够更加得心应手

接下来我要对Lodash的源码进行剖析学习
每天几个小方法,跟着我一起来学lodash吧


1、_.fill(array, value, [start=0], [end=array.length])

根据中文文档介绍,该方法能在array数组中用value的值进行替换,开始索引为start(如果没有该值,则默认为0),结束索引为end(如果没有该值,则默认为数组array的长度,同时不包含end的位置)
这个方法会改变 array(注:不是创建新数组)。

下面看中文文档介绍的例子:

JavaScript实用库:Lodash源码数组函数解析(五)fill、baseFill、findIndex、baseFindIndex、baseIteratee、findLastIndex_第1张图片

例子中:第一个例子,我们用字符串a对里面的三个元素进行了替换,因为没有start和end的值,所以默认为该数组的全部,下面的我就不说了。

下面我们来看源码;

function fill(array, value, start, end) {
  var length = array == null ? 0 : array.length;
  if (!length) {
    return [];
  }
  if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
    start = 0;
    end = length;
  }
  return baseFill(array, value, start, end);
}

module.exports = fill;

可以看到啊,该方法是基于核心函数baseFill等下我们来介绍它,还有一个isIterateeCall函数,为了不陷入死循环,这里直接说一下它的功能:检查给定参数是否来自迭代调用,如果不是就输出false。

也就是说符合if的条件得是,start大于0而且start的类型不是number类型而且array、value、start是我们迭代调用的参数,那么就使start的值为0,end的值为数组长度length。

最后就靠我们核心函数baseFill进行替换。


2、_.baseFill

这里没有中文文档的介绍,那么我们只能直接看源码了:

/**
 * The base implementation of `_.fill` without an iteratee call guard.
 *
 * @private
 * @param {Array} array The array to fill.
 * @param {*} value The value to fill `array` with.
 * @param {number} [start=0] The start position.
 * @param {number} [end=array.length] The end position.
 * @returns {Array} Returns `array`.
 */
function baseFill(array, value, start, end) {
  //获取数组长度
  var length = array.length;

  //将start化为整数类型
  start = toInteger(start);
  if (start < 0) {
    //如果start小于0,对start进行判断赋值
    //如果-start大于length则赋值为0,否则赋值为length + start
    start = -start > length ? 0 : (length + start);
  }
  //对end进行判断赋值,避免特殊情况
  //如果end的值没有定义或者值大于数组长度length则赋值为数组长度length
  //没有那两种情况则赋值整数化的end
  end = (end === undefined || end > length) ? length : toInteger(end);

  //如果end的值小于0,则将end的值加上数组长度length
  //因为数组的索引可以从后往前用负数表示,例如-1则是数组的倒数第一位
  //利用该方法可以将负数转化为正数
  if (end < 0) {
    end += length;
  }

  //这里为了end的值大于start做进一步处理
  //toLength方法能够将数据转化为长整数类型
  end = start > end ? 0 : toLength(end);
  //最后就是在While循环中对start与end索引之间的值进行替换(包括start不包括end)
  while (start < end) {
    array[start++] = value;
  }
  //最后输出替换的数组
  return array;
}

module.exports = baseFill;

解析过程写在了源码中,以后这样写这样更清晰直观


3、.findIndex(array, [predicate=.identity], [fromIndex=0])

根据中文文档介绍,该方法返回第一个通过 predicate 判断为真值的元素的索引值(index),而不是元素本身。

我们来看一下例子简单了解一下:
JavaScript实用库:Lodash源码数组函数解析(五)fill、baseFill、findIndex、baseFindIndex、baseIteratee、findLastIndex_第2张图片
每个例子都说一下原因吧:

第一个:我们的 predicate判断是一个函数,内容是 输出的o.user == ‘barney’ ,只有为这个值的时候,输出才为真,那么我们数组里面,第一个对象就满足我们的要求,也就输出的索引0

第二个:对应的不就是我们的第二个对象吗,所以输出索引为1

第三个:就是存在[‘active’, false]的元素,有人就问,为什么不是第二个对象,因为输出值只有一个,自然是靠前的输出,所以输出索引0

第四个:有人又问了,那现在为什么不是输出的第一个对象索引,不是都有active吗,不是输出靠前的吗?应为第一第二的对象的active对应的是false,为假,自然不符合条件啦,所以只有我们最后一个符合条件,输出索引2

下面我们来看源码:

function findIndex(array, predicate, fromIndex) {
  //依旧是获取数组的长度
  var length = array == null ? 0 : array.length;
  if (!length) {
    //如果数组的长度为0,则输出-1
    return -1;
  }
  //获取整数化fromIndex的值,它是开始搜索的位置,刚刚例子中都没有,这里说一下
  var index = fromIndex == null ? 0 : toInteger(fromIndex);

  //如果index的值小于0,进行处理
  if (index < 0) {
    //比较length+index与0的大小,取大的数赋值
    index = nativeMax(length + index, 0);
  }
  
  return baseFindIndex(array, baseIteratee(predicate, 3), index);
}

module.exports = findIndex;

这里得展示一下核心函数baseFindIndex的源码及功能才可以进行下一步的解析


4、_.baseFindIndex

由于中文文档没有介绍,所以只能来看源码了:

/**
 * The base implementation of `_.findIndex` and `_.findLastIndex` without
 * support for iteratee shorthands.
 *
 * @private
 * @param {Array} array The array to inspect.
 * @param {Function} predicate The function invoked per iteration.
 * @param {number} fromIndex The index to search from.
 * @param {boolean} [fromRight] Specify iterating from right to left.
 * @returns {number} Returns the index of the matched value, else `-1`.
 */
function baseFindIndex(array, predicate, fromIndex, fromRight) {
  //获取数组array的长度,以及赋值开始的索引给index,以及判断是否从右边开始
  var length = array.length,
      index = fromIndex + (fromRight ? 1 : -1);
  //循环判断确定位置索引,当if中的表达式为真时,输出索引
  while ((fromRight ? index-- : ++index < length)) {
    if (predicate(array[index], index, array)) {
      return index;
    }
  }
  return -1;
}

module.exports = baseFindIndex;

到了这里我们就差不多了解findIndex方法的过程了,没有fromRight,它即为假值于是在index赋值中index = formIndex - 1,
在while循环中也是 ++index < length,从左往右进行判断。

后面再说一下baseIteratee


5、_.baseIteratee

这个函数中文文档中也没有介绍,所以只能来看源码:

/**
 * The base implementation of `_.iteratee`.
 *
 * @private
 * @param {*} [value=_.identity] The value to convert to an iteratee.
 * @returns {Function} Returns the iteratee.
 */
function baseIteratee(value) {
  // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
  // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
  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);
}

module.exports = baseIteratee;

这个方法总的来说就一句话概括:封装遍历器(让遍历器不仅可以是函数,还可以是属性或者对象)


6、.findLastIndex(array, [predicate=.identity], [fromIndex=array.length-1])

根据中文文档介绍:这个方式类似 _.findIndex, 区别是它是从右到左的迭代集合array中的元素

我们来看例子:
JavaScript实用库:Lodash源码数组函数解析(五)fill、baseFill、findIndex、baseFindIndex、baseIteratee、findLastIndex_第3张图片这几个例子看似好像和 _.findIndex的例子差不多,但是里面的第三个例子就突出了它的不同,我之前说过 _.findIndex输出的索引都是靠左的,而这个优先输出靠右的,这就是他们的区别,我们来看源码

var nativeMax = Math.max,
    nativeMin = Math.min;

/**
 * This method is like `_.findIndex` except that it iterates over elements
 * of `collection` from right to left.
 *
 * @static
 * @memberOf _
 * @since 2.0.0
 * @category Array
 * @param {Array} array The array to inspect.
 * @param {Function} [predicate=_.identity] The function invoked per iteration.
 * @param {number} [fromIndex=array.length-1] The index to search from.
 * @returns {number} Returns the index of the found element, else `-1`.
 * @example
 *
 * var users = [
 *   { 'user': 'barney',  'active': true },
 *   { 'user': 'fred',    'active': false },
 *   { 'user': 'pebbles', 'active': false }
 * ];
 *
 * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
 * // => 2
 *
 * // The `_.matches` iteratee shorthand.
 * _.findLastIndex(users, { 'user': 'barney', 'active': true });
 * // => 0
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.findLastIndex(users, ['active', false]);
 * // => 2
 *
 * // The `_.property` iteratee shorthand.
 * _.findLastIndex(users, 'active');
 * // => 0
 */
function findLastIndex(array, predicate, fromIndex) {
  var length = array == null ? 0 : array.length;
  if (!length) {
    return -1;
  }
  var index = length - 1;
  if (fromIndex !== undefined) {
    index = toInteger(fromIndex);
    index = fromIndex < 0
      ? nativeMax(length + index, 0)
      : nativeMin(index, length - 1);
  }
  return baseFindIndex(array, baseIteratee(predicate, 3), index, true);
}

module.exports = findLastIndex;

于是我们就发现了最根本的地方,就是我们的核心函数baseFindIndex它的第四个参数为true,开启的fromRight参数,于是我们的判断就从右往左啦


今天就到这里啦,内容还是挺多的,好好消化一下

你可能感兴趣的:(前端)