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

lodash源码学习(2)

继续学习lodash,依然是数组的方法

“Array” Methods

_.indexOf(array, value, [fromIndex=0])

获取value在数组 array所在的索引值 使用 SameValueZero方式比较(第一个全等===的元素). 如果 fromIndex 值是负数, 则从array末尾起算

该方法依赖于strictIndexOf和baseIndexOf方法,先看它们的源码

//_strictIndexOf.js/** * _.indexOf的专业版本,对元素执行严格的比较方法(===) * * @param {Array} array 需要处理的数组. * @param {*} value 查找的值. * @param {number} fromIndex 查找的开始位置. * @returns {number} 返回第一个匹配的值的索引,或者-1. */function strictIndexOf(array, value, fromIndex) {  var index = fromIndex - 1,//数值索引      length = array.length;//数组长度  while (++index < length) {//遍历,如果数组中的值和查找的值相同,返回对应的index    if (array[index] === value) {      return index;    }  }  return -1;//返回-1}module.exports = strictIndexOf;
//_baseIndexOf.jsvar baseFindIndex = require(‘./_baseFindIndex‘),//baseFindIndex方法(见源码学习(1))    baseIsNaN = require(‘./_baseIsNaN‘),//判断是不是NaN    strictIndexOf = require(‘./_strictIndexOf‘);//strictIndexOf方法/** * _.indexOf的基本实现,不对fromIndex的范围进行检查 * * @param {Array} array 需要处理的数组. * @param {*} value 需要查找的值. * @param {number} fromIndex 查找的开始位置. * @returns {number} 返回第一个匹配的值的索引,或者-1. */function baseIndexOf(array, value, fromIndex) {    //如果value =http://www.mamicode.com/== value(也就是不为NaN),调用strictIndexOf方法,否则调用baseFindIndex方法,判断条件为是否为NaN    //并且将结果作为返回值返回  return value =http://www.mamicode.com/== value     ? strictIndexOf(array, value, fromIndex)    : baseFindIndex(array, baseIsNaN, fromIndex);}module.exports = baseIndexOf;

然后再看indexOf方法的源码

//indexOf.jsvar baseIndexOf = require(‘./_baseIndexOf‘),//baseIndexOf方法    toInteger = require(‘./toInteger‘);//转化为整形var nativeMax = Math.max;/** * * * @param {Array} array 需要处理的数组. * @param {*} value 需要查找的值. * @param {number} [fromIndex=0] 查找的开始位置. * @returns {number} 返回第一个匹配的值的索引,或者-1. * @example * * _.indexOf([1, 2, 1, 2], 2); * // => 1 * * // Search from the `fromIndex`. * _.indexOf([1, 2, 1, 2], 2, 2); * // => 3 */function indexOf(array, value, fromIndex) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回-1    return -1;  }  var index = fromIndex == null ? 0 : toInteger(fromIndex);//查找的起始位置,如果没有传入fromIndex则为0,否则为fromIndex  if (index < 0) {//如果index为负值,从末尾算起    index = nativeMax(length + index, 0);  }  return baseIndexOf(array, value, index);//调用baseIndexOf方法,并将结果作为返回值返回}module.exports = indexOf;

_.initial(array)

得到数组的除了最后一个元素以外的所有元素.

//initial.jsvar baseSlice = require(‘./_baseSlice‘);//同Array.slice方法/** *  * * @param {Array} array 需要处理的数组. * @returns {Array} 返回切好的数组. * @example * * _.initial([1, 2, 3]); * // => [1, 2] */function initial(array) {  var length = array == null ? 0 : array.length;//数组长度  return length ? baseSlice(array, 0, -1) : [];//如果不为空数组,调用baseSlice方法并将结果返回,否则返回空数组}module.exports = initial;

_.intersection([arrays])

取出各数组中都有的元素,使用 SameValueZero方式比较(===).

_.intersectionBy([arrays], [iteratee=_.identity])

和_.intersection很像,除了它接受一个遍历器被每个元素调用,生成计算之后的属性当他们比较的时候。遍历器interatee只接收一个参数(value)

_.intersectionWith([arrays], [comparator])

和_.intersection很像,除了它接受一个比较规则被每个元素调用,比较方法接受两个参数(arrVal,othVal)

这三个方法依赖于baseIntersection方法

//_baseIntersection.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 nativeMin = Math.min;/** * _.intersection的基本实现, 不支持遍历器的简写. * * @private * @param {Array} arrays 需要处理的数组. * @param {Function} [iteratee] 遍历器,作用于每个元素. * @param {Function} [comparator] 比较器,作用于每个元素. * @returns {Array} 返回一个数组包含给定所有数组中共有的元素. */function baseIntersection(arrays, iteratee, comparator) {  var includes = comparator ? arrayIncludesWith : arrayIncludes,//如果有比较器,为arrayIncludesWith,否则为arrayIncludes      length = arrays[0].length,//第一个数组的长度      othLength = arrays.length,//给定的所有数组的长度      othIndex = othLength,//给定所有数组的索引      caches = Array(othLength),//创建一个缓存给定数组个数的数组      maxLength = Infinity,//最大长度      result = [];//返回结果  //遍历给定的数组  while (othIndex--) {    var array = arrays[othIndex];//当前数组    if (othIndex && iteratee) {//如果不是第一个数组,并且有遍历器,对当前数组调用遍历器遍历每个元素      array = arrayMap(array, baseUnary(iteratee));//当前数组为调用之后的数组    }    maxLength = nativeMin(array.length, maxLength);//数组的最大长度    //如果该数组长度超过120就创建Set缓存数组中并添加到caches中(用于优化)    caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))      ? new SetCache(othIndex && array)      : undefined;  }  array = arrays[0];//给定所有数组中的第一个  var index = -1,//数组索引      seen = caches[0];//第一个缓存数组,初始为undefined或者new SetCache(0)  outer:  //遍历第一个数组  while (++index < length && result.length < maxLength) {    var value = http://www.mamicode.com/array[index],//数组元素        computed = iteratee ? iteratee(value) : value;//如果有遍历器,对改元素调用,得到计算后的值    value = (comparator || value !== 0) ? value : 0;//如果有比较器或者value不为0,value为value,否则为0    if (!(seen//如果seen有值了,判断是否含有computed,否则判断结果中是否含有computed,如果都没有computed          ? cacheHas(seen, computed)          : includes(result, computed, comparator)        )) {      othIndex = othLength;//其他数组的索引,初始为给定数组的长度      //遍历给定的数组,除了第一个      while (--othIndex) {        var cache = caches[othIndex];//缓存数组中的值        //太长的数组就是cache,短的就是arrays[index],判断是否含有computed,如果没有,跳过此次循环        if (!(cache              ? cacheHas(cache, computed)              : includes(arrays[othIndex], computed, comparator))            ) {          continue outer;        }      }      if (seen) {//如果缓存存在,将computed添加到缓存中        seen.push(computed);      }      result.push(value);//将value添加到结果数组中    }  }  return result;//返回结果数组}module.exports = baseIntersection;

对应的方法在baseIntersection上进行处理

//intersection.jsvar arrayMap = require(‘./_arrayMap‘),//同Array.map    baseIntersection = require(‘./_baseIntersection‘),//baseIntersection方法    baseRest = require(‘./_baseRest‘),//创建可以使用rest参数的方法    castArrayLikeObject = require(‘./_castArrayLikeObject‘);//创建一个类似数组的对象,如果不是为空数组/** *  * @param {...Array} [arrays] 需要处理的所有数组. * @returns {Array} 返回一个数组包含给定所有数组中共有的元素. * @example * * _.intersection([2, 1], [2, 3]); * // => [2] */var intersection = baseRest(function(arrays) {//创建具备rest参数的方法  var mapped = arrayMap(arrays, castArrayLikeObject);//将所有数组转化为类似数组的对象  return (mapped.length && mapped[0] === arrays[0])//如果传入的数组个数不为0,并且第一个参数为数组,调用baseIntersection方法传入mapped,并将结果作为返回值返回,否则返回空数组    ? baseIntersection(mapped)    : [];});module.exports = intersection;
//intersectionBy.jsvar arrayMap = require(‘./_arrayMap‘),//同Array.map    baseIntersection = require(‘./_baseIntersection‘),//baseIntersection方法    baseIteratee = require(‘./_baseIteratee‘),//遍历器封装    baseRest = require(‘./_baseRest‘), //创建具有rest参数的方法    castArrayLikeObject = require(‘./_castArrayLikeObject‘),//创建类似数组的对象    last = require(‘./last‘);//取得数组的最后一个元素/** *  * @param {...Array} [arrays] 需要处理的数组. * @param {Function} [iteratee=_.identity] 遍历器被每个元素调用. * @returns {Array} 返回一个数组包含给定所有数组中共有的元素. * @example * * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); * // => [2.1] * * // The `_.property` iteratee shorthand. * _.intersectionBy([{ ‘x‘: 1 }], [{ ‘x‘: 2 }, { ‘x‘: 1 }], ‘x‘); * // => [{ ‘x‘: 1 }] */var intersectionBy = baseRest(function(arrays) {//创建具备rest参数的方法  var iteratee = last(arrays),//遍历器为最后一个参数      mapped = arrayMap(arrays, castArrayLikeObject);//将所有数组转化为类似数组的对象  if (iteratee === last(mapped)) {//如果遍历器和mapped最后一个一样(也就是最后一个参数为数组)    iteratee = undefined;//不存在遍历器  } else {    mapped.pop();//否则将mapped最后一个元素去掉(遍历器转化的元素)  }  return (mapped.length && mapped[0] === arrays[0])  //如果传入的数组个数不为0,并且第一个参数为数组,调用baseIntersection方法传入mapped和iteratee,并且支持属性的简写,并将结果作为返回值返回,否则返回空数组    ? baseIntersection(mapped, baseIteratee(iteratee, 2))    : [];});module.exports = intersectionBy;
//intersectionWith.jsvar arrayMap = require(‘./_arrayMap‘),//同Array.map    baseIntersection = require(‘./_baseIntersection‘),//baseIntersection方法    baseRest = require(‘./_baseRest‘),//创建具有rest参数的方法    castArrayLikeObject = require(‘./_castArrayLikeObject‘),//创建类似数组的对象    last = require(‘./last‘);//取得数组的最后一个元素/** * * @param {...Array} [arrays] 需要处理的数组. * @param {Function} [comparator] 比较方法. * @returns {Array} 返回一个数组包含给定所有数组中共有的元素. * @example * * var objects = [{ ‘x‘: 1, ‘y‘: 2 }, { ‘x‘: 2, ‘y‘: 1 }]; * var others = [{ ‘x‘: 1, ‘y‘: 1 }, { ‘x‘: 1, ‘y‘: 2 }]; * * _.intersectionWith(objects, others, _.isEqual); * // => [{ ‘x‘: 1, ‘y‘: 2 }] */var intersectionWith = baseRest(function(arrays) {//创建具有rest参数的方法  var comparator = last(arrays),//比较器为最后一个元素      mapped = arrayMap(arrays, castArrayLikeObject);//将所有数组转化为类似数组的对象  comparator = typeof comparator == ‘function‘ ? comparator : undefined;//比较器如果不为function,则为undefined  if (comparator) {//如果有比较器,将mapped最后一个元素去掉(比较器转化的元素)    mapped.pop();  }  //如果传入的数组个数不为0,并且第一个参数为数组,调用baseIntersection方法传入mapped和comparator,并将结果作为返回值返回,否则返回空数组  return (mapped.length && mapped[0] === arrays[0])    ? baseIntersection(mapped, undefined, comparator)    : [];});module.exports = intersectionWith;

_.join(array, [separator=‘,‘])

 转化数组为字符串,用指定的分割符将每个元素连接起来.

//join.jsvar arrayProto = Array.prototype;//数组的原型var nativeJoin = arrayProto.join;//原生join方法/** * * @param {Array} array 需要转化的数组. * @param {string} [separator=‘,‘] 分割符. * @returns {string} 返回连接起来的字符串. * @example * * _.join([‘a‘, ‘b‘, ‘c‘], ‘~‘); * // => ‘a~b~c‘ */function join(array, separator) {  return array == null ? ‘‘ : nativeJoin.call(array, separator);//如果数组为空,返回空字符串,否则调用原生的join方法,并将结果返回}module.exports = join;

_.last(array)

得到数组的最后一个元素

//last.js/** * * @param {Array} array 需要处理的数组. * @returns {*} 返回数组的最后一个元素. * @example * * _.last([1, 2, 3]); * // => 3 */function last(array) {  var length = array == null ? 0 : array.length;  return length ? array[length - 1] : undefined;//不解释}module.exports = last;

_.lastIndexOf(array, value, [fromIndex=array.length-1])

和_.indexOf很像,但是是从右到左开始遍历

该方法依赖于strictLastIndexOf方法

//_strictLastIndexOf.js/** * _.lastIndexOf的专业版本,对元素执行严格的比较方法(===). * * @param {Array} array 需要处理的数组. * @param {*} value 需要查找的值. * @param {number} fromIndex 查找的开始位置. * @returns {number} 返回第一个匹配的元素的索引,或者-1. */function strictLastIndexOf(array, value, fromIndex) {  var index = fromIndex + 1;//数值索引  while (index--) {    if (array[index] === value) {//遍历,如果数组中的值和查找的值相同,返回对应的index      return index;    }  }  return index;//返回index(如果没有找到,index的值为-1)}module.exports = strictLastIndexOf;

再看lastIndexOf方法的源码

//lastIndexOf.jsvar baseFindIndex = require(‘./_baseFindIndex‘),//baseFindIndex方法(见源码学习(1))    baseIsNaN = require(‘./_baseIsNaN‘),//判断是否为NaN    strictLastIndexOf = require(‘./_strictLastIndexOf‘),//strictLastIndexOf方法    toInteger = require(‘./toInteger‘);//转化为整型var nativeMax = Math.max,//原生最大值方法    nativeMin = Math.min;//原生最小值方法/** * * @param {Array} array 需要处理的数组. * @param {*} value 需要查找的值. * @param {number} [fromIndex=array.length-1] 查找的开始位置. * @returns {number} 返回匹配的第一个元素的索引,或者-1. * @example * * _.lastIndexOf([1, 2, 1, 2], 2); * // => 3 * * // Search from the `fromIndex`. * _.lastIndexOf([1, 2, 1, 2], 2, 2); * // => 1 */function lastIndexOf(array, value, fromIndex) {  var length = array == null ? 0 : array.length;//数组长度  if (!length) {//如果为空数组,返回-1    return -1;  }  var index = length;//数组索引  if (fromIndex !== undefined) {//如果有起始位置    index = toInteger(fromIndex);//转换为整形    index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);//判断起始位置,在0到length-1之间,如果为负,从末尾算起  }  return value =http://www.mamicode.com/== value//如果不是NaN,调用strictLastIndexOf方法,否则调用baseFindIndex方法,并且传入判断条件为baseIsNaN    ? strictLastIndexOf(array, value, index)    : baseFindIndex(array, baseIsNaN, index, true);}module.exports = lastIndexOf;

_.nth(array, [n=0])

得到数组指定索引的值,如果索引为负值,从数组末尾算起.

该方法依赖于baseNth方法

//_baseNth.jsvar isIndex = require(‘./_isIndex‘);//是否为正确的索引/** * _.nth的基本实现,不强制参数 * * @private * @param {Array} array 需要查询的数组 * @param {number} n 查找元素的index. * @returns {*} 返回查找到的元素. */function baseNth(array, n) {  var length = array.length;//数组长度  if (!length) {//如果为空数组,返回空数组    return;  }  n += n < 0 ? length : 0;//n<0从末尾算,否则就是n  return isIndex(n, length) ? array[n] : undefined;//如果是正确的索引,返回索引对应的值,否则返回undefined}module.exports = baseNth;

再看nth.js

//nth.jsvar baseNth = require(‘./_baseNth‘),//baseNth方法    toInteger = require(‘./toInteger‘);//转化为整形/** * * @param {Array} array 需要查询的数组. * @param {number} [n=0] 查找元素的index.. * @returns {*} 返回查找到的元素. * @example * * var array = [‘a‘, ‘b‘, ‘c‘, ‘d‘]; * * _.nth(array, 1); * // => ‘b‘ * * _.nth(array, -2); * // => ‘c‘; */function nth(array, n) {  return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;//不解释}module.exports = nth;

_.pull(array, [values])

移除数组array中所有和 values 相等的元素,使用 SameValueZero 进行全等比较.

_.pullAll(array, values)

和_.pull很像除了它接受一个需要移除的元素的数组

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

这个方法和_.pullAll很像除了它接受一个遍历方法被每个元素调用,遍历方法接受一个参数(value)

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

这4个方法都依赖于basePullAll方法

//_basePullAll.jsvar arrayMap = require(‘./_arrayMap‘),//同Array.map    baseIndexOf = require(‘./_baseIndexOf‘),//同Array.indexOf,上面已分析    baseIndexOfWith = require(‘./_baseIndexOfWith‘),//类似baseIndexOf,除了接受一个比较方法    baseUnary = require(‘./_baseUnary‘),//创建一个只有一个参数的方法,忽略其他的参数    copyArray = require(‘./_copyArray‘);//拷贝数组var arrayProto = Array.prototype;//数组原形var splice = arrayProto.splice;//原生splice方法/** * _.pullAllBy的基本实现,不支持遍历器的简写 * * @private * @param {Array} array 需要修改的数组. * @param {Array} values 需要移除的元素. * @param {Function} [iteratee] 遍历器,对每个元素调用. * @param {Function} [comparator] 比较器,对每个元素调用. * @returns {Array} 返回修改之后的数组. */function basePullAll(array, values, iteratee, comparator) {  var indexOf = comparator ? baseIndexOfWith : baseIndexOf,//选择indexOf方法,如果传入比较器为baseIndexOfWith,否则为baseIndexOf      index = -1,//数值索引      length = values.length,//数组长度      seen = array;//获取一个array的引用  if (array === values) {//如果需要移除的元素和需要修改的数组一样,拷贝一份values    values = copyArray(values);  }  if (iteratee) {//如过存在遍历器,对数组进行遍历操作    seen = arrayMap(array, baseUnary(iteratee));  }  //遍历需要移除的数组  while (++index < length) {    var fromIndex = 0,//元素在数组中的开始位置        value = http://www.mamicode.com/values[index],//需要移除的元素        computed = iteratee ? iteratee(value) : value;//如果有遍历器对value进行调用,得到 计算后的value(也就是computed)    //循环执行indexOf方法,如果seen中,直到找不到computed为止    while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {      if (seen !== array) {//seen和array不相等即存在遍历器,对seen执行splice方法移除fromIndex的元素        splice.call(seen, fromIndex, 1);      }      //对array执行splice方法移除fromIndex的元素      splice.call(array, fromIndex, 1);    }  }  return array;//返回修改后的array}module.exports = basePullAll;

相对应的方法的源码

//pullAll.jsvar basePullAll = require(‘./_basePullAll‘);//basePullAll方法/** * * @param {Array} array 需要修改的数组. * @param {Array} values 需要移除的值. * @returns {Array} 返回修改后的数组. * @example * * var array = [‘a‘, ‘b‘, ‘c‘, ‘a‘, ‘b‘, ‘c‘]; * * _.pullAll(array, [‘a‘, ‘c‘]); * console.log(array); * // => [‘b‘, ‘b‘] */function pullAll(array, values) {  return (array && array.length && values && values.length)    ? basePullAll(array, values)    : array;//不解释}module.exports = pullAll;
//pull.jsvar baseRest = require(‘./_baseRest‘),//创建具有rest参数的方法    pullAll = require(‘./pullAll‘);/** * * @param {Array} array 需要修改的数组. * @param {...*} [values] The values to remove. * @returns {Array} Returns `array`. * @example * * var array = [‘a‘, ‘b‘, ‘c‘, ‘a‘, ‘b‘, ‘c‘]; * * _.pull(array, ‘a‘, ‘c‘); * console.log(array); * // => [‘b‘, ‘b‘] */var pull = baseRest(pullAll);//将pullAll转换成可以使用rest参数的方法(pull(array,...values))module.exports = pull;
//pullAllBy.jsvar baseIteratee = require(‘./_baseIteratee‘),//封装遍历器    basePullAll = require(‘./_basePullAll‘);//basePullAll方法/** * * @param {Array} array 需要修改的数组. * @param {Array} values 需要移除的值. * @param {Function} [iteratee=_.identity] 遍历器,被每个元素调用. * @returns {Array} 返回修改后的数组. * @example * * var array = [{ ‘x‘: 1 }, { ‘x‘: 2 }, { ‘x‘: 3 }, { ‘x‘: 1 }]; * * _.pullAllBy(array, [{ ‘x‘: 1 }, { ‘x‘: 3 }], ‘x‘); * console.log(array); * // => [{ ‘x‘: 2 }] */function pullAllBy(array, values, iteratee) {  return (array && array.length && values && values.length)    ? basePullAll(array, values, baseIteratee(iteratee, 2))    : array;//不解释}module.exports = pullAllBy;
//pullWidth.jsvar basePullAll = require(‘./_basePullAll‘);//basePullAll方法/** * * @param {Array} array 需要修改的数组. * @param {Array} values 需要移除的元素. * @param {Function} [comparator] 比较器被每个元素调用. * @returns {Array} 返回修改后的数组. * @example * * var array = [{ ‘x‘: 1, ‘y‘: 2 }, { ‘x‘: 3, ‘y‘: 4 }, { ‘x‘: 5, ‘y‘: 6 }]; * * _.pullAllWith(array, [{ ‘x‘: 3, ‘y‘: 4 }], _.isEqual); * console.log(array); * // => [{ ‘x‘: 1, ‘y‘: 2 }, { ‘x‘: 5, ‘y‘: 6 }] */function pullAllWith(array, values, comparator) {  return (array && array.length && values && values.length)    ? basePullAll(array, values, undefined, comparator)    : array;//不解释}module.exports = pullAllWith;

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

lodash源码学习(2)