首页 > 代码库 > lodash源码学习(1)

lodash源码学习(1)

  前端开发这个行业这几年发展速度太快,各种新技术不断更新,从es5到es6再到es7,从grunt,browserify到webpack,gulp,rollup,还有什么postcss,typescript,flow...,一直都在学习新技术,作为一个才工作不久的新人,感觉内心有点浮躁了,想巩固一下基础,之前听别人说lodash的源码很不错,所以学习学习。我不是什么大牛,如果有什么分析得不对的,大家请务必要原谅我。。。。话不多说,lodash版本4.17.4,开始!。

1.“Array” Methods

_.chunk(array, [size=1])

将一个数组拆分成多个数组的块,然后把这些块组成新的数组

//chunk.js//同Array.slice方法var baseSlice = require(‘./_baseSlice‘),     //是否是一个遍历方法的参数,也就是需要和Array.map的参数一样,第一个是值,第二个是索引,第三个是对象本身    isIterateeCall = require(‘./_isIterateeCall‘),     //转化成整型    toInteger = require(‘./toInteger‘);var nativeCeil = Math.ceil,//上舍入    nativeMax = Math.max;//最大值/** *@param {Array} array 需要处理的数组 *@param {Number} size 每个数组块的长度 *@param {Object} guard 让chunk方法可以作为一个遍历方法,比如作为Array.map的参数(不知道有什么用)  *@returns {Array} 返回处理后的数组   */function chunk(array, size, guard) {  //判断是否传入guard,如果传入,判断是否是遍历方法的参数,如果是size=1,否则为传入size和0的最大值  //如果没传,判断是否传入size,如果没传,size=1,否则为传入size和0的最大值  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) {  //如果为空,或者传入负的size,返回空数组    return [];  }  var index = 0,//切数组块的的起始位置      resIndex = 0,//返回的数组的索引      result = Array(nativeCeil(length / size));//返回的数组  //循环,每次向result添加一个size的数组块,并且将index向后移size个位置,直到index到了原始数组的末尾  while (index < length) {    result[resIndex++] = baseSlice(array, index, (index += size));  }  return result;//返回切好的数组}module.exports = chunk;

 _.compact(array)

创建一个新数组并包含原数组中所有的非假值元素。

//compact.js/** *@param {Array} array 需要处理的数组 *@returns {Array} 返回处理后的数组   */function compact(array) {  var index = -1,//数组索引      length = array == null ? 0 : array.length,//数组长度      resIndex = 0,//结果数组索引      result = [];//结果数组       while (++index < length) {//遍历原数组    var value =http://www.mamicode.com/ array[index];    if (value) {//如果是真值,就将它加入到结果数组中,并且让resIndex加1      result[resIndex++] = value;    }  }  return result;//返回结果数组}module.exports = compact;    

_.concat(array, [values])

创建一个新数组包含原来的数组和所有添加的元素和数组

//concat.jsvar arrayPush = require(‘./_arrayPush‘),//同Array.push方法,第一个参数是原数组,第二个是需要添加的值得数组集合    baseFlatten = require(‘./_baseFlatten‘),//数组扁平化,后面再分析,比如[1,[2,3],[4,5,[6]]] => [1,2,3,4,5,6]    copyArray = require(‘./_copyArray‘),//拷贝数组    isArray = require(‘./isArray‘);//Array.isArray方法的引用。/** *@param {Array} array 需要处理的数组 *@param {...*} [values] 需要添加的元素或数组 *@returns {Array} 返回处理后的数组   */function concat() {  var length = arguments.length;//参数个数  if (!length) {//没有参数,返回空数组    return [];  }  var args = Array(length - 1), //包含需要添加的数组或元素的数组      array = arguments[0],//原数组      index = length;//参数索引  while (index--) {//遍历参数,将除了第一个参数的其他参数加入args中    args[index - 1] = arguments[index];  }  //如果第一个参数是数组,先复制一份(这样就不会修改原数组),然后将args扁平化一级([1,[2,[3]]] => [1,2,[3]])之后添加进拷贝的数组中,并返回添加之后的数组  //如果第一个参数不是数组,直接将其作为空数组的第一个元素([array]),然后将args扁平化一级([1,[2,[3]]] => [1,2,[3]])之后添加进该数组,并返回添加之后的数组  return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));}module.exports = concat;

_.difference(array, [values])

创建一个新数组,其结果为原数组中不包含过滤数组中的值。

_.differenceBy(array, [values], [iteratee=_.identity])

_.difference很像,除了他接受一个遍历函数被每个原数组和过滤数组中的值调用,调用之后再进行过滤。

_.differenceWith(array, [values], [comparator])

_.difference很像,除了他接受一个比较方法被每个原数组和过滤数组中的值调用,比较方法接受两个参数(arrVal原数组的值,othVal过滤数组的值),比较结果为true则过滤掉。

这三个方法都依赖于baseDifference方法,先看源码。

//_baseDifference.jsvar SetCache = require(‘./_SetCache‘), //Set缓存数组    arrayIncludes = require(‘./_arrayIncludes‘),//同Array.includes方法    arrayIncludesWith = require(‘./_arrayIncludesWith‘),//同Array.includes方法,除了他接受一个比较方法    arrayMap = require(‘./_arrayMap‘),//同Array.map    baseUnary = require(‘./_baseUnary‘),//创建一个只有一个参数的方法,忽略其他的参数    cacheHas = require(‘./_cacheHas‘);//判断缓存中是否存在某个元素var LARGE_ARRAY_SIZE = 200;//数组最大长度/** * @param {Array} array 需要处理的数组. * @param {Array} values 需要过滤的数组. * @param {Function} [iteratee] 遍历器,被每个元素调用. * @param {Function} [comparator] 比较器,被每个元素调用. * @returns {Array} 返回过滤后的数组. */function baseDifference(array, values, iteratee, comparator) {  var index = -1,//原数组索引      includes = arrayIncludes,//引用arrayIncludes      isCommon = true,//是否正常过滤      length = array.length,//数组长度      result = [],//返回结构      valuesLength = values.length;//过滤数组长度  if (!length) {//如果原数组为空或者空数组,返回空数组    return result;  }  if (iteratee) {//如果有遍历器,先对过滤数组进行遍历操作    values = arrayMap(values, baseUnary(iteratee));  }  if (comparator) {//如果有比较器,includes就引用arrayIncludesWith,并且不正常过滤    includes = arrayIncludesWith;    isCommon = false;  }  else if (values.length >= LARGE_ARRAY_SIZE) {//如果过滤数组的长度大于最大数组长度    includes = cacheHas;//includes引用cacheHas    isCommon = false;//不正常过滤    values = new SetCache(values);//过滤数组等于缓存之后的数组(用于优化,暂时不分析)  }  //遍历原数组  outer:  while (++index < length) {    var value = http://www.mamicode.com/array[index],//每次遍历的原数组中的元素        computed = iteratee == null ? value : iteratee(value);//如果有遍历器,对该元素调用一次,得到计算后的cumputed,否则computed和value一样    value = (comparator || value !== 0) ? value : 0;    if (isCommon && computed === computed) {//正常过滤并且computed不为NaN      var valuesIndex = valuesLength;//过滤数组的索引      while (valuesIndex--) {        if (values[valuesIndex] === computed) {//如果这个元素在过滤数组中存在,跳过,          continue outer;        }      }      result.push(value);//如果不存在,添加添加进结果数组中    }    else if (!includes(values, computed, comparator)) {//非正常过滤,调用includes方法,如果通过比较器的规则不包含,将该元素添加进结果数组      result.push(value);    }  }  return result;//返回过滤后的数组}module.exports = baseDifference;

相对应的方法都是在baseDiffrerece的基础上进行扩展的

//difference.jsvar baseDifference = require(‘./_baseDifference‘),//baseDifference方法    baseFlatten = require(‘./_baseFlatten‘),//数组扁平化    baseRest = require(‘./_baseRest‘),//创建可以使用rest参数的方法    isArrayLikeObject = require(‘./isArrayLikeObject‘);//是否是一个类似数组的对象/** * * @param {Array} 需要处理的数组. * @param {...Array} [values] 需要过滤的值. * @returns {Array} 返回过滤后的数组. */var difference = baseRest(function(array, values) {//创建一个具备rest参数的方法  //如果array是一个类似数组的对象,调用baseDifference方法,并且将所有过滤数组扁平化一级,比如difference(arr,[1,2],[3,4]) => baseDifference(arr,[1,2,3,4])  //如果不是,返回一个空数组  return isArrayLikeObject(array)    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))    : [];});module.exports = difference;
//differenceBy.jsvar baseDifference = require(‘./_baseDifference‘),//baseDifference方法    baseFlatten = require(‘./_baseFlatten‘),//数组扁平化    baseIteratee = require(‘./_baseIteratee‘),//封装遍历器(让遍历器不仅可以是函数,还可以是属性或者对象)    baseRest = require(‘./_baseRest‘),//创建可以使用rest参数的方法    isArrayLikeObject = require(‘./isArrayLikeObject‘),//是否是一个类似数组的对象    last = require(‘./last‘);//得到数组的最后一个元素/** * @param {Array} 需要处理的数组. * @param {...Array} [values] 需要过滤的值. * @param {Function} [iteratee=_.identity] 遍历器,对每个元素进行调用. * @returns {Array} 返回过滤后的数组. */var differenceBy = baseRest(function(array, values) {//创建一个具备rest参数的方法  var iteratee = last(values);//遍历器为values的最后一个参数  if (isArrayLikeObject(iteratee)) {//如果这个参数是类似数组的对象,遍历器为undefined(也就是并没有传入遍历器)    iteratee = undefined;  }  //如果array是类似数组的对象,调用baseDifference,并且将所有过滤数组扁平化一级,再传入创建的遍历器  //如果不是,返回一个空数组  return isArrayLikeObject(array)    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), baseIteratee(iteratee, 2))    : [];});module.exports = differenceBy;
//differenceWith.jsvar baseDifference = require(‘./_baseDifference‘),//同上    baseFlatten = require(‘./_baseFlatten‘),    baseRest = require(‘./_baseRest‘),    isArrayLikeObject = require(‘./isArrayLikeObject‘),    last = require(‘./last‘);/** * @param {Array} array 需要处理的数组. * @param {...Array} [values] 需要过滤的值. * @param {Function} [comparator] 比较器,对每个元素进行调用. * @returns {Array} 返回过滤后的数组. */var differenceWith = baseRest(function(array, values) {//创建一个具备rest参数的方法  var comparator = last(values);//比较器为values的最后一个参数  if (isArrayLikeObject(comparator)) {//如果这个参数是类似数组的对象,比较器为undefined(也就是并没有传入比较器)    comparator = undefined;  }  //如果array是类似数组的对象,调用baseDifference,并且将所有过滤数组扁平化一级,并且不传遍历器,再传入比较器  return isArrayLikeObject(array)    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)    : [];});module.exports = differenceWith;

_.drop(array, [n=1])

将 array 中的前 n 个元素去掉,然后返回剩余的部分

//drop.jsvar baseSlice = require(‘./_baseSlice‘),//同Array.slice    toInteger = require(‘./toInteger‘);//转化为整型/** *  * @param {Array} array 需要处理的数组. * @param {number} [n=1] 需要去掉的个数. * @param- {Object} [guard] 使这个方法能够作为遍历器被调用,比如_.map(drop). * @returns {Array} 返回处理后的数组. */function drop(array, n, guard) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回空数组    return [];  }  n = (guard || n === undefined) ? 1 : toInteger(n);//将n转为整型  return baseSlice(array, n < 0 ? 0 : n, length);//调用baseSlice对数组从n位置进行切割,并返回切好的数组}module.exports = drop;

_.dropRight(array, [n=1])

将 array 尾部的 n 个元素去除,并返回剩余的部分。

//dropRight.jsvar baseSlice = require(‘./_baseSlice‘),//同Array.slice    toInteger = require(‘./toInteger‘);//转化为整型/** *  * @param {Array} array 需要处理的数组. * @param {number} [n=1] 需要去掉的个数. * @param- {Object} [guard] 使这个方法能够作为遍历器被调用,比如_.map(dropRight). * @returns {Array} 返回处理后的数组. */function dropRight(array, n, guard) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回空数组    return [];  }  n = (guard || n === undefined) ? 1 : toInteger(n);//将n转为整型  n = length - n;//剩下的个数  return baseSlice(array, 0, n < 0 ? 0 : n);//调用baseSlice对数组从0位置进行切割n个,并返回切好的数组}module.exports = dropRight;

_.dropRightWhile(array, [predicate=_.identity])

 从末尾对数组进行截取,从第一个不满足predicate 条件的元素开始截取数组。predicate接受三个参数(value,index,array)

_.dropWhile(array, [predicate=_.identity])

从开始对数组进行截取,从第一个不满足predicate 条件的元素开始截取数组。predicate接受三个参数(value,index,array)

这两个方法依赖于baseWhile方法,先看源码

//_baseWhile.jsvar baseSlice = require(‘./_baseSlice‘);//同Array.slice/** *_.dropWhile和_.takeWhile的基本实现,但是不支持遍历器的简写(不能直接写一个属性或对象进行遍历) * * @param {Array} array 需要处理的数组. * @param {Function} predicate 迭代判断条件. * @param {boolean} [isDrop] 指定是移除还是获取这些元素. * @param {boolean} [fromRight] 指定从开始还是末尾开始判断. * @returns {Array} 返回处理后的数组. */function baseWhile(array, predicate, isDrop, fromRight) {  var length = array.length,//数组长度      index = fromRight ? length : -1;//数组索引,如果是从末尾判断,则为length,否则为0  //遍历每个元素,并且调用判断方法,直到判断结果为false,然后得到此时的index  while ((fromRight ? index-- : ++index < length) &&    predicate(array[index], index, array)) {}    //如果是删除元素,如果从末尾开始,调用baseSlice(0,index+1),否则调用baseSlice(index,length)  //如果是获取元素,如果从末尾开始,调用baseSlice(index+1,length),否则调用baseSlice(0,index)  //最后返回切好的数组  return isDrop    ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))    : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));}module.exports = baseWhile;

相对应的方法都是在baseWhile的基础上进行扩展的

//dropRightWhile.jsvar baseIteratee = require(‘./_baseIteratee‘),//封装遍历器    baseWhile = require(‘./_baseWhile‘);//baseWhile方法/** *  * @param {Array} array 需要处理的数组. * @param {Function} [predicate=_.identity] 迭代判断条件. * @returns {Array} 返回切好的数组. */function dropRightWhile(array, predicate) {  //如果array存在,并且不为空数组,调用baseWhile方法,传入该数组,遍历器,然后指定从右边开始移除  //否则返回空数组  return (array && array.length)    ? baseWhile(array, baseIteratee(predicate, 3), true, true)    : [];}module.exports = dropRightWhile;
//dropWhile.jsvar baseIteratee = require(‘./_baseIteratee‘),//封装遍历器    baseWhile = require(‘./_baseWhile‘);//baseWhile方法/** *  * @param {Array} array 需要处理的数组. * @param {Function} [predicate=_.identity] 迭代判断条件. * @returns {Array} 返回切好的数组. */function dropWhile(array, predicate) {  //如果array存在,并且不为空数组,调用baseWhile方法,传入该数组,遍历器,然后指定从左边开始移除  //否则返回空数组  return (array && array.length)    ? baseWhile(array, baseIteratee(predicate, 3), true)    : [];}module.exports = dropWhile;

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

使用 value 值来填充(也就是替换) array,从start位置开始, 到end位置结束(但不包含end位置)

此方法依赖于baseFill方法,先看源码

//_baseFill.jsvar toInteger = require(‘./toInteger‘),//转换为整型    toLength = require(‘./toLength‘);//转换为可以使用的length/** * 使用 value 值来填充(也就是替换) array,从start位置开始, 到end位置结束(但不包含end位置)  * * @private * @param {Array} array 需要处理的数组. * @param {*} value 填充的值. * @param {number} [start=0] 填充的开始位置 * @param {number} [end=array.length] 填充的结束位置. * @returns {Array} 返回处理后的数组. */function baseFill(array, value, start, end) {  var length = array.length;//数组长度  start = toInteger(start);//转换为整型  if (start < 0) {//如果start为负值,从末尾开始算,-1就是最后一个元素,依次计算,如果最后大于数组的长度,就是0    start = -start > length ? 0 : (length + start);  }  //对end进行判断,取得合适的end  end = (end === undefined || end > length) ? length : toInteger(end);  if (end < 0) {//如果start为负值,从末尾开始算,-1就是最后一个元素,依次计算,如果最后大于数组的长度,就是0    end += length;  }  //如果start大于end,end等于0,否则将end转为可用的length  end = start > end ? 0 : toLength(end);  //循环,每次start+1直到start=end  while (start < end) {    array[start++] = value;//将对应索引的元素替换为value  }  return array;//返回该数组}module.exports = baseFill;

再看fill.js

//fill.jsvar baseFill = require(‘./_baseFill‘),//baseFill方法    isIterateeCall = require(‘./_isIterateeCall‘);//判断是否为遍历器的参数(value,index,array)/**  * * @param {Array} array 需要处理的数组. * @param {*} value 填充的值. * @param {number} [start=0] 填充的开始位置 * @param {number} [end=array.length] 填充的结束位置. * @returns {Array} 返回处理后的数组. */function fill(array, value, start, end) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回空数组    return [];  }  //如果start存在且不为number且为遍历器,那么start=0,end=length(也就是说将fill作为参数传入map之类的方法,暂时不知道有什么用)  if (start && typeof start != ‘number‘ && isIterateeCall(array, value, start)) {    start = 0;    end = length;  }  return baseFill(array, value, start, end); //调用baseFill并且将结果数组返回}module.exports = fill;

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

对数组从开始进行查找,该方法返回符合判断条件的第一个元素的索引

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

对数组从末尾进行查找,该方法返回符合判断条件的第一个元素的索引

这两个方法依赖于baseFindIndex方法,先看源码

//_baseFindIndex.js/** *_.findIndex和_.findLastIndex的基本实现,但是不支持遍历方法的简写(不能直接写一个属性或对象进行遍历) * * @private * @param {Array} array 需要处理的数组. * @param {Function} predicate 判断方法,对每个元素调用. * @param {number} fromIndex 开始查找的位置. * @param {boolean} [fromRight] 指定从开始还是末尾开始搜索. * @returns {number} 返回匹配的值的索引,否则返回-1. */function baseFindIndex(array, predicate, fromIndex, fromRight) {  var length = array.length,//数组长度      index = fromIndex + (fromRight ? 1 : -1);//数组索引  //循环,对每个元素调用判断方法,如果结果为true,返回对应的index  while ((fromRight ? index-- : ++index < length)) {    if (predicate(array[index], index, array)) {      return index;    }  }  return -1;//返回-1}module.exports = baseFindIndex;

相对应的方法都是在baseFindIndex的基础上进行扩展的

//findIndex.jsvar baseFindIndex = require(‘./_baseFindIndex‘),//baseFindIndex方法    baseIteratee = require(‘./_baseIteratee‘),//封装遍历器(让遍历器不仅可以是函数,还可以是属性或者对象)    toInteger = require(‘./toInteger‘);//转换为整型var nativeMax = Math.max;/** * * @param {Array} array 需要处理的数组. * @param {Function} [predicate=_.identity] 遍历器,对每个元素调用. * @param {number} [fromIndex=0] 开始查找的位置. * @returns {number} 返回匹配的值的索引,否则返回-1. */function findIndex(array, predicate, fromIndex) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回-1    return -1;  }  var index = fromIndex == null ? 0 : toInteger(fromIndex);//开始查找的索引  if (index < 0) {//如果index为负值,从末尾开始算,-1就是最后一个元素,依次计算,如果最后大于数组的长度,就是0    index = nativeMax(length + index, 0);  }  //调用baseFindIndex,并且将遍历方法封装,然后将结果作为返回值返回  return baseFindIndex(array, baseIteratee(predicate, 3), index);}module.exports = findIndex;
//findLastIndex.jsvar baseFindIndex = require(‘./_baseFindIndex‘),//baseFindIndex方法    baseIteratee = require(‘./_baseIteratee‘),//封装遍历器(让遍历器不仅可以是函数,还可以是属性或者对象)    toInteger = require(‘./toInteger‘);//转换为整型var nativeMax = Math.max,    nativeMin = Math.min;/** * * @param {Array} array 需要处理的数组. * @param {Function} [predicate=_.identity] 遍历器,对每个元素调用. * @param {number} [fromIndex=0] 开始查找的位置. * @returns {number} 返回匹配的值的索引,否则返回-1. */function findLastIndex(array, predicate, fromIndex) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回-1    return -1;  }  var index = length - 1;//开始查找的索引  if (fromIndex !== undefined) {//如果有fromIndex,进行比较,得到正确的index(负值反向且不能超过数组长度)    index = toInteger(fromIndex);    index = fromIndex < 0      ? nativeMax(length + index, 0)      : nativeMin(index, length - 1);  }  //调用baseFindIndex方法,并且封装遍历器,并且指定从右边查找,最后将结果作为返回值返回  return baseFindIndex(array, baseIteratee(predicate, 3), index, true);}module.exports = findLastIndex;

 

_.find(collection, [predicate=_.identity], [fromIndex=0])

从开始对集合进行查找,该方法返回符合判断条件的第一个元素

_.findLast(collection, [predicate=_.identity], [fromIndex=0])

从末尾对集合进行查找,该方法返回符合判断条件的第一个元素

这两个方法是属于集合的方法,依赖于createFind方法和上面的findIndex和findLastIndex方法,所以就在这里一起分析了,先看createFind的源码

//_createFind.jsvar baseIteratee = require(‘./_baseIteratee‘),    isArrayLike = require(‘./isArrayLike‘),    keys = require(‘./keys‘);/** * 创建一个_.find或者_.findLast方法 * * @private * @param {Function} findIndexFunc 查找集合index的方法. * @returns {Function} 返回新的查找方法. */function createFind(findIndexFunc) {  return function(collection, predicate, fromIndex) {    var iterable = Object(collection);//将集合转为对象    if (!isArrayLike(collection)) {//如果不是类似数组的对象(就是常规的对象)      var iteratee = baseIteratee(predicate, 3);      collection = keys(collection);//集合为这个对象的key的集合      predicate = function(key) { return iteratee(iterable[key], key, iterable); };//重写判断方法    }    var index = findIndexFunc(collection, predicate, fromIndex);//调用findIndexFunc方法,取得索引    //如果index>-1 就取得这个索引对应的值,否则为undefined,并且将结果返回    return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;  };}module.exports = createFind;

find方法相当于是调用createFind传入findIndex,lastFind方法相当于是调用createFind传入findLastIndex

//find.jsvar createFind = require(‘./_createFind‘),//createFind方法    findIndex = require(‘./findIndex‘);//findIndex方法/** *  * @param {Array} array 需要处理的数组. * @param {Function} [predicate=_.identity] 遍历器,对每个元素调用. * @param {number} [fromIndex=0] 开始查找的位置. * @returns {number} 返回匹配的值,或者undefined. */var find = createFind(findIndex);//创建find方法module.exports = find;
//findLast.jsvar createFind = require(‘./_createFind‘),//createFind方法    findLastIndex = require(‘./findLastIndex‘);//findIndex方法/** *  * @param {Array} array 需要处理的数组. * @param {Function} [predicate=_.identity] 遍历器,对每个元素调用. * @param {number} [fromIndex=0] 开始查找的位置. * @returns {number} 返回匹配的值,或者undefined. */var findLast = createFind(findLastIndex);//创建find方法module.exports = findLast;

_.head(array)/_.first(array)

得到数组的第一个元素

//head.js/** * * @param {Array} array 需要处理的数组. * @returns {*} Returns 数组的第一个元素. */function head(array) {  return (array && array.length) ? array[0] : undefined;//不解释}module.exports = head;
//first.jsmodule.exports = require(‘./head‘);

_.flatten(array)

对数组执行扁平化一级操作

_.flattenDeep(array)

对数组递归的执行扁平化操作.

_.flattenDepth(array, [depth=1])

对数组执行扁平化depth级操作.

数组扁平化的几种方法依赖于baseFlatten方法,先看源码

//_baseFlatten.jsvar arrayPush = require(‘./_arrayPush‘),//同Array.push    isFlattenable = require(‘./_isFlattenable‘);//是否可以扁平化/** * _.flatten的基本实现,支持是否限制扁平化操作 * * @param {Array} array 需要处理的数组. * @param {number} depth 扁平化的深度. * @param {boolean} [predicate=isFlattenable] 判断是否执行扁平化操作,对每个元素进行调用. * @param {boolean} [isStrict] 是否遵守predicate的检查. * @param {Array} [result=[]] 初始化结果值. * @returns {Array} 返回扁平化之后的数组. */function baseFlatten(array, depth, predicate, isStrict, result) {  var index = -1,//数组索引      length = array.length;//数组长度  predicate || (predicate = isFlattenable);//如果没有传入判断方法,这判断方法为isFlattenable(只有可以执行扁平化就执行)  result || (result = []);//如果没有传入的初始的结果数组,则结果为空数组  //遍历数组中的每个元素  while (++index < length) {    var value = http://www.mamicode.com/array[index];//元素值    if (depth > 0 && predicate(value)) {//如果深度大于0并且通过了检查      if (depth > 1) {//如果深度大于1(还需要扁平化),递归调用自身,并且depth-1,否则将这个元素值添加到结果数组        baseFlatten(value, depth - 1, predicate, isStrict, result);      } else {        arrayPush(result, value);      }    } else if (!isStrict) {//如果不需要遵守判断规则,直接将value添加到结果中      result[result.length] = value;    }  }  return result;//返回结果数组}module.exports = baseFlatten;

相对应的方法都是在baseFlatten的基础上扩展的

//flatten.jsvar baseFlatten = require(‘./_baseFlatten‘);//baseFlatten方法/** * * @param {Array} array 需要处理的数组. * @returns {Array} Returns 扁平化之后数组. * @example * * _.flatten([1, [2, [3, [4]], 5]]); * // => [1, 2, [3, [4]], 5] */function flatten(array) {  var length = array == null ? 0 : array.length;//数组长度  return length ? baseFlatten(array, 1) : [];//如果不是空数组,调用baseFlatten(只扁平化一级),并将结果返回,否则,返回空数组}module.exports = flatten;
//flattenDeep.jsvar baseFlatten = require(‘./_baseFlatten‘);//baseFlatten方法var INFINITY = 1 / 0;//无限大/** * * @param {Array} array 需要处理的数组. * @returns {Array} 返回扁平化之后的数组. */function flattenDeep(array) {  var length = array == null ? 0 : array.length;//数组长度  return length ? baseFlatten(array, INFINITY) : [];//如果不是空数组,调用baseFlatten(递归调用,直到不能扁平化为止),并将结果返回,否则,返回空数组}module.exports = flattenDeep;
//flattenDepth.jsvar baseFlatten = require(‘./_baseFlatten‘),//baseFlatten方法    toInteger = require(‘./toInteger‘);//转化为整型/** * @param {Array} array 需要处理的数组. * @param {number} [depth=1] 扁平化的深度. * @returns {Array} 返回扁平化之后的数组. */function flattenDepth(array, depth) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回空数组    return [];  }  depth = depth === undefined ? 1 : toInteger(depth);//扁平化的深度  return baseFlatten(array, depth);//递归调用depth次baseFlatten,然后将结果作为返回值返回。}module.exports = flattenDepth;

_.fromPairs(pairs)

将键值对的数组转化为键值对的对象

//fromPairs.js/** *  * @param {Array} pairs 键值对的数组. * @returns {Object} 返回新的对象. * @example * * _.fromPairs([[‘a‘, 1], [‘b‘, 2]]); * // => { ‘a‘: 1, ‘b‘: 2 } */function fromPairs(pairs) {  var index = -1,//数组索引      length = pairs == null ? 0 : pairs.length,//数组长度      result = {};//结果对象  //遍历数组中的值  while (++index < length) {    var pair = pairs[index];//键值对的值    result[pair[0]] = pair[1];//将第一个作为键,第二个作为值添加到结果对象中  }  return result;//返回结果对象}module.exports = fromPairs;

先到这里了,下次继续,慢慢来,一步一个脚印~~~

lodash源码学习(1)