欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-03 13:13:10
...

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


JavaScript实用库:Lodash源码数组函数解析(五)fill、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

例子中:第一个例子,我们用字符串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
每个例子都说一下原因吧:

第一个:我们的 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这几个例子看似好像和 _.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参数,于是我们的判断就从右往左啦


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

相关标签: 前端

上一篇:

下一篇: