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

lodash源码学习(3)

“Array” Methods

_.pullAt(array, [indexes])

移除数组中在indexs中对应索引的元素,并返回这些元素

这个方法依赖于basePullAt方法

//_basePullAt.jsvar baseUnset = require(‘./_baseUnset‘),//_.unset的基本实现,移除对象中对应路径的元素(暂时不分析)    isIndex = require(‘./_isIndex‘);//是否是一个正确的索引var arrayProto = Array.prototype;//数组原型var splice = arrayProto.splice;//原生splice方法/** * _.pullAt的基本实现,不支持单独的索引值(rest参数形式),不能捕获删除的元素。 * * @private * @param {Array} array 需要修改的数组. * @param {number[]} indexes 需要移除的索引值的数组. * @returns {Array} 返回修改之后的数组. */function basePullAt(array, indexes) {  var length = array ? indexes.length : 0,//需要移除的值的个数      lastIndex = length - 1;//最后一个需要移除的索引的索引    //从indexes末尾遍历(从开始遍历删除元素会改变索引)  while (length--) {    var index = indexes[length];//需要移除的索引    if (length == lastIndex || index !== previous) {//如果index不是privious(防止重复的索引)      var previous = index;//上一个移除的索引      if (isIndex(index)) {//如果是一个正确的索引,将数组中这个索引的元素移除        splice.call(array, index, 1);      } else {//如果不是,将数组中这个路径的的元素移除        baseUnset(array, index);      }    }  }  return array;//返回修改之后的数组}module.exports = basePullAt;

对应的源码为

//.pullAt.jsvar arrayMap = require(‘./_arrayMap‘),//同Array.map    baseAt = require(‘./_baseAt‘),//_.at的的基本实现,返回一个数组包含对象中对应路径的元素(暂时不分析)    basePullAt = require(‘./_basePullAt‘),//basePullAt方法    compareAscending = require(‘./_compareAscending‘),//排序规则,简单排序(如果a小于b,那么a在b的前面)    flatRest = require(‘./_flatRest‘),//baseRest的特殊版本,将rest参数扁平化一级    isIndex = require(‘./_isIndex‘);//是否是正确的索引/** *  * * @param {Array} array 需要修改的数组. * @param {...(number|number[])} [indexes] 需要移除的元素indexes. * @returns {Array} 返回一个新数组包含所有移除的元素. * @example * * var array = [‘a‘, ‘b‘, ‘c‘, ‘d‘]; * var pulled = _.pullAt(array, [1, 3]); * * console.log(array); * // => [‘a‘, ‘c‘] * * console.log(pulled); * // => [‘b‘, ‘d‘] */var pullAt = flatRest(function(array, indexes) {//创建具备rest参数的方法,并且将rest参数扁平化一级,比如(func(arr,[1,2,3],[4,5]) => func(arr,[1,2,3,4,5]))  var length = array == null ? 0 : array.length,//数组长度      result = baseAt(array, indexes);//得到对应索引的所有元素  //调用basePullAt方法,先并且判断每个索引值是否正确,然后对索引进行排序之后传入当做indexes  basePullAt(array, arrayMap(indexes, function(index) {    return isIndex(index, length) ? +index : index;  }).sort(compareAscending));  return result;//返回结果数组});module.exports = pullAt;

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

移除数组中所有通过判断条件返回的true的元素,然后返回包含所有移除元素的数组,判断条件接受三个参数(value,index,array)

//remove.jsvar baseIteratee = require(‘./_baseIteratee‘),//遍历器封装    basePullAt = require(‘./_basePullAt‘);//basePullAt方法/** * @param {Array} array 需要修改的数组. * @param {Function} [predicate=_.identity] 判断条件. * @returns {Array} 返回包含所有移除的元素的数组. * @example * * var array = [1, 2, 3, 4]; * var evens = _.remove(array, function(n) { *   return n % 2 == 0; * }); * * console.log(array); * // => [1, 3] * * console.log(evens); * // => [2, 4] */function remove(array, predicate) {  var result = [];//返回结果数组  if (!(array && array.length)) {//如果没有传入array或者为空数组,返回空数组    return result;  }  var index = -1,//数组索引      indexes = [],//需要移除的索引      length = array.length;//数组长度  predicate = baseIteratee(predicate, 3);//将判断条件封装,支持简写  while (++index < length) {//遍历数组中的元素    var value = http://www.mamicode.com/array[index];//当前元素    if (predicate(value, index, array)) {//调用判断方法返回true,将这个元素加入到结果中,将当前索引值加到indexes中      result.push(value);      indexes.push(index);    }  }  basePullAt(array, indexes);//调用basePullAt方法移除indexes中的元素  return result;//返回结果数组}module.exports = remove;

_.reverse(array)

颠倒数组中元素的顺序.

//reserve.jsvar arrayProto = Array.prototype;//数组原型var nativeReverse = arrayProto.reverse;//原生reverse方法的引用/** * * @param {Array} array 需要修改的数组. * @returns {Array} 返回修改后的数组. * @example * * var array = [1, 2, 3]; * * _.reverse(array); * // => [3, 2, 1] * * console.log(array); * // => [3, 2, 1] */function reverse(array) {  return array == null ? array : nativeReverse.call(array);//不解释}module.exports = reverse;

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

创建一个数组片段从数组中的start位置开始,到end位置结束,但不包括end.

这个方法依赖于baseSlice方法,在之前的方法中也经常需要使用这个方法。

//_baseSlice.js/** * _.slice的基本实现. * * @private * @param {Array} array 需要切割的数组. * @param {number} [start=0] 切割开始位置. * @param {number} [end=array.length] 切割结束位置. * @returns {Array} 返回切好的数组片段. */function baseSlice(array, start, end) {  var index = -1,//数组索引      length = array.length;//数组长度  if (start < 0) {//start小于0从末尾算起    start = -start > length ? 0 : (length + start);  }  end = end > length ? length : end;//end不能超过length  if (end < 0) {//end小于0从末尾算起    end += length;  }  length = start > end ? 0 : ((end - start) >>> 0);// 需要切割的长度,借助右移位运算符 用零填充length 左边空出的位,这样做的好处是如果 length 未定义就取0  start >>>= 0;  var result = Array(length);//返回结果数组  //遍历,从start位置开始,将对应的值添加到结果数组中,直到添加length个元素  while (++index < length) {    result[index] = array[index + start];  }  return result;//返回结果数组}module.exports = baseSlice;

slice方法

//slice.jsvar baseSlice = require(‘./_baseSlice‘),//baseSlice方法    isIterateeCall = require(‘./_isIterateeCall‘),//是否是遍历器的参数(value,index,array)    toInteger = require(‘./toInteger‘);//转化成整型/** *  * * @param {Array} array 需要切割的数组. * @param {number} [start=0] 切割的开始位置. * @param {number} [end=array.length] 切割的结束位置. * @returns {Array} 返回切好的数组片段. */function slice(array, start, end) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回空数组    return [];  }  //如果是遍历器的参数,start=0,end=length(不知道有啥用)  if (end && typeof end != ‘number‘ && isIterateeCall(array, start, end)) {    start = 0;    end = length;  }  else {      //没有传start从开始,也就是返回完整的数组    start = start == null ? 0 : toInteger(start);    //没有传end就切到数组结尾    end = end === undefined ? length : toInteger(end);  }  return baseSlice(array, start, end);//调用baseSlice方法,并将结果作为返回值返回}module.exports = slice;

_.sortedIndex(array, value)

 执行一个二分法检索决定value应该被插入数组中的位置,使原数组保持它的排序。

_.sortedIndexBy(array, value, [iteratee=_.identity])

这个方法和_.sortedIndex很像,除了它接受一个遍历器被value和array中的每个元素调用以计算排序位置,
遍历器接受一个参数(value)

_.sortedIndexOf(array, value)

 和_.indexOf很像,除了它执行一个二分法检索在一个已将排序的数组上

_.sortedLastIndex(array, value)

这个方法和_.sortedIndex很像,除了他返回value被插入到文档中的最高的index

_.sortedLastIndexBy(array, value, [iteratee=_.identity])

和_.sortedLastIndex很像,除了它接受一个遍历器被value和array中的每个元素调用以计算排序位置,
遍历器接受一个参数(value)

_.sortedLastIndexOf(array, value)

和_.lastIndexOf很像,除了它执行一个二分法检索在一个已将排序的数组上

sorted系列方法,用于对排序的数组的操作,依赖于baseSortedIndexBy方法和baseSortedIndex方法

//_baseSortedIndexBy.jsvar isSymbol = require(‘./isSymbol‘);//判断是否为Symbol(js的第七种数据类型,表示一种唯一值)var MAX_ARRAY_LENGTH = 4294967295,//数组最大长度    MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1;//数组最大indexvar nativeFloor = Math.floor,//原生下舍入方法    nativeMin = Math.min;//原生最小值方法/** * _.sortedIndexBy和_.sortedLastIndexBy的基本实现,对每个元素调用遍历器计算排序排名,遍历器接受一个参数(value) * * @param {Array} array 需要处理的数组. * @param {*} value 需要评估的值. * @param {Function} iteratee 遍历器,被每个元素调用. * @param {boolean} [retHighest] 指定是否返回最高的符合条件的index. * @returns {number} 返回value应该被插入数组中的位置 */function baseSortedIndexBy(array, value, iteratee, retHighest) {  value = iteratee(value);//对value调用遍历器  var low = 0,//开始位置      high = array == null ? 0 : array.length,//结束位置      valIsNaN = value !== value,//是否是NaN      valIsNull = value =http://www.mamicode.com/== null,//是否为空      valIsSymbol = isSymbol(value),//是否是Symbol      valIsUndefined = value =http://www.mamicode.com/== undefined;//是否是undefined  //循环,直到开始位置等于结束位置  while (low < high) {    var mid = nativeFloor((low + high) / 2),//中间位置        computed = iteratee(array[mid]),//对中间位置的值调用遍历器得到computed        othIsDefined = computed !== undefined,//是否为undefined        othIsNull = computed === null,//是否为null        othIsReflexive = computed === computed,//是否为正常的值        othIsSymbol = isSymbol(computed);//是否是Symbol    if (valIsNaN) {//如果value是NaN      var setLow = retHighest || othIsReflexive;//是否可以设置新的开始位置    } else if (valIsUndefined) {//如果value为undefined,      setLow = othIsReflexive && (retHighest || othIsDefined);    } else if (valIsNull) {//如果value为空值      setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);    } else if (valIsSymbol) {//如果value是Symbol      setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);    } else if (othIsNull || othIsSymbol) {//如果中间位置的值为空或者为Symbol      setLow = false;    } else {//正常情况,如果中间的值比评估的值小,那么重新设置开始位置      setLow = retHighest ? (computed <= value) : (computed < value);    }    //如果setLow为true,设置起始位置为数组中间位置+1    if (setLow) {      low = mid + 1;    } else {//如果已经不需要在设置起始位置了,设置high为当前范围的中间位置      high = mid;    }  }  return nativeMin(high, MAX_ARRAY_INDEX);//返回high和最大数组长度的索引的最小值}module.exports = baseSortedIndexBy;
//_baseSortedIndex.jsvar baseSortedIndexBy = require(‘./_baseSortedIndexBy‘),//baseSortedIndexBy方法    identity = require(‘./identity‘),//返回第一个参数    isSymbol = require(‘./isSymbol‘);//是否是Symbolvar MAX_ARRAY_LENGTH = 4294967295,//最大数组长度    HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;//最大数组长度的一半/** * _.sortedIndex和_.sortedLastIndex的基本实现,执行一个二分法检索决定value应该被插入数组中的位置,使原数组保持它的排序。 * * @private * @param {Array} array 需要处理的已经排序的数组. * @param {*} value 需要评估的值. * @param {boolean} [retHighest] 指定是否返回最高的符合条件的index. * @returns {number} 返回value应该被插入数组中的位置 */function baseSortedIndex(array, value, retHighest) {  var low = 0,//起始位置      high = array == null ? low : array.length;//结束位置  if (typeof value =http://www.mamicode.com/= ‘number‘ && value === value && high <= HALF_MAX_ARRAY_LENGTH) {      //循环,直到开始位置等于结束位置    while (low < high) {      var mid = (low + high) >>> 1,//中间位置          computed = array[mid];//中间位置的值      if (computed !== null && !isSymbol(computed) &&          (retHighest ? (computed <= value) : (computed < value))) {//正常情况,如果中间的值比评估的值小,那么设置开始位置为中间位置+1        low = mid + 1;      } else {//否则设置high为中间位置        high = mid;      }    }    return high;//返回结束位置  }     //如果value不是数字,或者为NaN或者长度太长,调用baseSortedIndexBy,并将结果作为返回值返回  return baseSortedIndexBy(array, value, identity, retHighest);}module.exports = baseSortedIndex;

对应的方法

sortedIndex

//sortedIndex.jsvar baseSortedIndex = require(‘./_baseSortedIndex‘);//baseSortedIndex方法/**. * * @static * @memberOf _ * @since 0.1.0 * @category Array * @param {Array} array 需要处理的已经排序的数组. * @param {*} value 需要评估的值. * @returns {number} 返回value应该被插入数组中的位置. * @example * * _.sortedIndex([30, 50], 40); * // => 1 */function sortedIndex(array, value) {  return baseSortedIndex(array, value);}module.exports = sortedIndex;

baseIndexBy

//baseIndexBy.jsvar baseIteratee = require(‘./_baseIteratee‘),//封装遍历器    baseSortedIndexBy = require(‘./_baseSortedIndexBy‘);//baseSortedIndexBy方法/** *  * * @static * @memberOf _ * @since 4.0.0 * @category Array * @param {Array} array 需要处理的已经排序的数组. * @param {*} value 需要评估的值. * @param {Function} [iteratee=_.identity] 遍历器,被每个元素调用. * @returns {number} 返回value应该被插入数组中的位置. * @example * * var objects = [{ ‘x‘: 4 }, { ‘x‘: 5 }]; * * _.sortedIndexBy(objects, { ‘x‘: 4 }, function(o) { return o.x; }); * // => 0 * * // The `_.property` iteratee shorthand. * _.sortedIndexBy(objects, { ‘x‘: 4 }, ‘x‘); * // => 0 */function sortedIndexBy(array, value, iteratee) {  return baseSortedIndexBy(array, value, baseIteratee(iteratee, 2));//不解释}module.exports = sortedIndexBy;

sortedIndexOf

//sortedIndexOf.jsvar baseSortedIndex = require(‘./_baseSortedIndex‘),//baseSortedIndex方法    eq = require(‘./eq‘);//判断是否相等/** * * * @param {Array} array 需要处理的数组. * @param {*} value 需要查找的值. * @returns {number} 返回匹配的索引值,或者-1. * @example * * _.sortedIndexOf([4, 5, 5, 5, 6], 5); * // => 1 */function sortedIndexOf(array, value) {  var length = array == null ? 0 : array.length;//数组长度  if (length) {    var index = baseSortedIndex(array, value);//调用baseSortedIndex获取应该插入index    if (index < length && eq(array[index], value)) {//如果不是插入最后一个并且数组中index的值等于value,返回这个index      return index;    }  }  return -1;//返回-1}module.exports = sortedIndexOf;

sortedLastIndex

//sortedLastIndex.jsvar baseSortedIndex = require(‘./_baseSortedIndex‘);//baseSortedIndex方法/** * * @param {Array} array 需要处理的数组. * @param {*} value 需要评估的值. * @returns {number} 返回value应该被插入数组中的位置. * @example * * _.sortedLastIndex([4, 5, 5, 5, 6], 5); * // => 4 */function sortedLastIndex(array, value) {  return baseSortedIndex(array, value, true);//不解释}module.exports = sortedLastIndex;

sortedLastIndexBy

//sortedLastIndexBy.jsvar baseIteratee = require(‘./_baseIteratee‘),//遍历器封装    baseSortedIndexBy = require(‘./_baseSortedIndexBy‘);//baseSortedIndexBy方法/** * * @param {Array} array 需要处理的数组. * @param {*} value 需要评估的值. * @param {Function} [iteratee=_.identity] 遍历器,被每个元素调用. * @returns {number} 返回value应该被插入数组中的位置. * @example * * var objects = [{ ‘x‘: 4 }, { ‘x‘: 5 }]; * * _.sortedLastIndexBy(objects, { ‘x‘: 4 }, function(o) { return o.x; }); * // => 1 * * // The `_.property` iteratee shorthand. * _.sortedLastIndexBy(objects, { ‘x‘: 4 }, ‘x‘); * // => 1 */function sortedLastIndexBy(array, value, iteratee) {//不解释  return baseSortedIndexBy(array, value, baseIteratee(iteratee, 2), true);}module.exports = sortedLastIndexBy;

sortedLastIndexOf

//sortedLastIndexOf.jsvar baseSortedIndex = require(‘./_baseSortedIndex‘),//baseSortedIndex方法    eq = require(‘./eq‘);//判断是否相等/** *  * @param {Array} array 需要处理的数组. * @param {*} value 需要查找的值. * @returns {number} 返回匹配的元素的index,或者-1. * @example * * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); * // => 3 */function sortedLastIndexOf(array, value) {  var length = array == null ? 0 : array.length;//数组长度  if (length) {//如果不为空数组    var index = baseSortedIndex(array, value, true) - 1;//调用baseSortedIndex获取索引    if (eq(array[index], value)) {//如果数组中index位置的值等于value,返回这个index      return index;    }  }  return -1;//返回-1}module.exports = sortedLastIndexOf;

_.sortedUniq(array)

 返回数组中唯一的值,和_.uniq很像,除了这是用来处理和优化排序数组的

_.sortedUniqBy(array, [iteratee])

和_.sortedUniq很像,除了它接受一个遍历方法被每个元素调用

这两个方法依赖于baseSortedUniq方法

//_baseSortedUniq.jsvar eq = require(‘./eq‘);//判断是否相等/** * _.sortedUniq和_.sortedUniqBy的基本实现,不支持遍历器的简写 * * @private * @param {Array} array 需要修改的数组. * @param {Function} [iteratee] 遍历器,被每个元素调用. * @returns {Array} 返回新的没有重复的数组. */function baseSortedUniq(array, iteratee) {  var index = -1,//数组索引      length = array.length,//数组长度      resIndex = 0,//返回值索引      result = [];//返回数组  //遍历array  while (++index < length) {    var value = http://www.mamicode.com/array[index],//当前元素        computed = iteratee ? iteratee(value) : value;//如果有遍历器进行调用,得到computed    if (!index || !eq(computed, seen)) {//如果index为0或者computed和seen不相等      var seen = computed;//当前存储的计算的值      result[resIndex++] = value =http://www.mamicode.com/== 0 ? 0 : value;//将这个value存入结果中    }  }  return result;//返回结果}module.exports = baseSortedUniq;

对应方法

sortedUniq

//sortedUniq.jsvar baseSortedUniq = require(‘./_baseSortedUniq‘);//baseSortedUniq方法/** * * * @param {Array} array 需要处理的数组. * @returns {Array} 返回新的没有重复的数组. * @example * * _.sortedUniq([1, 1, 2]); * // => [1, 2] */function sortedUniq(array) {//不解释  return (array && array.length)    ? baseSortedUniq(array)    : [];}module.exports = sortedUniq;

sortedUniqBy

//sortedUniqBy.jsvar baseIteratee = require(‘./_baseIteratee‘),//便利器封装    baseSortedUniq = require(‘./_baseSortedUniq‘);//baseSortedUniq方法/** *  * * @param {Array} array 需要处理的数组. * @param {Function} [iteratee] 遍历器被每个元素调用. * @returns {Array} 返回新的没有重复的数组. * @example * * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); * // => [1.1, 2.3] */function sortedUniqBy(array, iteratee) {//不解释  return (array && array.length)    ? baseSortedUniq(array, baseIteratee(iteratee, 2))    : [];}module.exports = sortedUniqBy;

_.tail(array)

 返回数组中除了第一个元素之外的所有元素.

//tail.jsvar baseSlice = require(‘./_baseSlice‘);//baseSlice方法/** * * * @param {Array} array 需要查询的数组. * @returns {Array} 返回切好的数组片段. * @example * * _.tail([1, 2, 3]); * // => [2, 3] */function tail(array) {  var length = array == null ? 0 : array.length;//数组长度  return length ? baseSlice(array, 1, length) : [];//如果不为空数组,调用baseSlice方法从1位置切割数组并返回,否则返回空数组}module.exports = tail;

一天一点进步,一步一个脚印~~~

lodash源码学习(3)