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(注:不是创建新数组)。
下面看中文文档介绍的例子:
例子中:第一个例子,我们用字符串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),而不是元素本身。
我们来看一下例子简单了解一下:
每个例子都说一下原因吧:
第一个:我们的 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中的元素
我们来看例子:
这几个例子看似好像和 _.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参数,于是我们的判断就从右往左啦
今天就到这里啦,内容还是挺多的,好好消化一下