lodash源码学习(5)

继续学习lodash,现在开始是collection部分,集合可以是数组,也可以是类似数组的对象。

“Collection” Methods

_.countBy(collection, [iteratee=_.identity])

 创建一个对象,它的key值为集合中的所有元素调用iteratee之后的不同值,每个key相应的value为集合中调用iteratee得到的key值的数量。

这个方法是一个聚合函数,依赖于createAggregator方法,createAggregate方法又依赖于baseAggregator和arrayAggregator方法。先看源码

baseAggregator

//_baseAggregator.js

var baseEach = require('./_baseEach');//同Array.forEach

/**
 * 累加集合中的所有元素到累加器对象中,通过遍历器转换相应的key值,通过setters设置对应的value.
 *
 * @private
 * @param {Array|Object} collection 需要处理的集合.
 * @param {Function} setter 设置累加器中的值的函数.
 * @param {Function} iteratee 遍历器用来转换累加器中的key值.
 * @param {Object} accumulator 累加器初始化对象.
 * @returns {Function} 返回累加器(源码中这里返回的类型是Function,但是个人觉得应该是Object).
 */
function baseAggregator(collection, setter, iteratee, accumulator) {
  //遍历集合中的每个元素,调用setter
  baseEach(collection, function(value, key, collection) {
    setter(accumulator, value, iteratee(value), collection);
  });
  return accumulator;
}

module.exports = baseAggregator;

arrayAggregator

//_arrayAggregator.js

/**
 * baseAggregator的特殊版本,针对于array
 *
 * @private
 * @param {Array} [array] 需要处理的数组.
 * @param {Function} setter 设置累加器中的值得函数.
 * @param {Function} iteratee 遍历器用来转换累加器中的key值
 * @param {Object} accumulator 初始化累加对象.
 * @returns {Function} 返回累加器(源码中这里返回的类型是Function,但是个人觉得应该是Object).
 */
function arrayAggregator(array, setter, iteratee, accumulator) {
  var index = -1,//数组索引
      length = array == null ? 0 : array.length;//数组长度

  while (++index < length) {//遍历数组,调用setter
    var value = array[index];
    setter(accumulator, value, iteratee(value), array);
  }
  return accumulator;//返回累加器
}

module.exports = arrayAggregator;

createAggregator

//_createAggregator.js

var arrayAggregator = require('./_arrayAggregator'),//数组聚合函数
    baseAggregator = require('./_baseAggregator'),//基础聚合函数
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    isArray = require('./isArray');//是否是数组

/**
 * 创建一个类似_.groupBy的聚合函数。
 *
 * @private
 * @param {Function} setter 设置累加器中的值得函数.
 * @param {Function} [initializer] 累加器的初始化设定.
 * @returns {Function} 返回新的聚合函数.
 */
function createAggregator(setter, initializer) {
  return function(collection, iteratee) {//返回的聚合函数
    var func = isArray(collection) ? arrayAggregator : baseAggregator,//如果是数组调用arrayAggregator,否则调用baseAggregator
        accumulator = initializer ? initializer() : {};//如果有累加器初始设定,调用,否则初始为空对象

    return func(collection, setter, baseIteratee(iteratee, 2), accumulator);//调用func并将结果作为返回值返回
  };
}

module.exports = createAggregator;

再看countBy的源码

//countBy.js

var baseAssignValue = require('./_baseAssignValue'),//对对象进行赋值(见源码学习(4))
    createAggregator = require('./_createAggregator');//创建聚合函数

var objectProto = Object.prototype;//对象原型

var hasOwnProperty = objectProto.hasOwnProperty;//原生hasOwnProperty方法。

/**
 *
 * @param {Array|Object} collection 需要迭代的集合.
 * @param {Function} [iteratee=_.identity] 遍历器,用于转换key值.
 * @returns {Object} 返回组合的聚合对象。
 * @example
 *
 * _.countBy([6.1, 4.2, 6.3], Math.floor);
 * // => { '4': 1, '6': 2 }
 *
 * // The `_.property` iteratee shorthand.
 * _.countBy(['one', 'two', 'three'], 'length');
 * // => { '3': 2, '5': 1 }
 */
var countBy = createAggregator(function(result, value, key) {//创建一个聚合函数,传入setter函数
  if (hasOwnProperty.call(result, key)) {//如果结果中有对应的key值,就让这个值加1
    ++result[key];
  } else {
    baseAssignValue(result, key, 1);//如果没有key值,设置这个key的值为1
  }
});

module.exports = countBy;

_.forEach(collection, [iteratee=_.identity])/_.each(collection, [iteratee=_.identity])

遍历集合中的元素,对每个元素调用遍历器,遍历器接受三个参数(value, index|key, collection),如果调用遍历器之后返回false,则中断遍历

这个方法依赖于arrayEach和baseEach方法

arrayEach

//_arrayEach.js

/**
 * _.forEach的特殊版本,不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要迭代的数组.
 * @param {Function} iteratee 遍历器,每次迭代的时候调用.
 * @returns {Array} 返回这个数组.
 */
function arrayEach(array, iteratee) {
  var index = -1,//数组索引
      length = array == null ? 0 : array.length;//数组长度

  while (++index < length) {//遍历数组,调用iteratee,如果返回false,跳出循环
    if (iteratee(array[index], index, array) === false) {
      break;
    }
  }
  return array;//返回这个数组
}

module.exports = arrayEach;

baseEach

//_baseEach.js

var baseForOwn = require('./_baseForOwn'),//遍历本身可枚举属性的方法(baseForOwn(object, iteratee))
    createBaseEach = require('./_createBaseEach');//createBaseEach方法

/**
 * _.forEach的基本实现,不支持遍历器的简写
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} iteratee 遍历器,每次迭代的时候调用.
 * @returns {Array|Object} 返回这个集合.
 */
var baseEach = createBaseEach(baseForOwn);//调用createBaseEach方法,传入eachFunc参数为baseForOwn

module.exports = baseEach;

baseEach依赖的createBaseEach方法

//_createBaseEach.js

var isArrayLike = require('./isArrayLike');//是否是类似数组(是否含有length属性)

/**
 * 创建一个baseEach或baseEachRight方法
 *
 * @private
 * @param {Function} eachFunc 遍历集合的方法.
 * @param {boolean} [fromRight] 指定遍历从左还是从右·.
 * @returns {Function} 返回新的遍历函数.
 */
function createBaseEach(eachFunc, fromRight) {
  return function(collection, iteratee) {
    if (collection == null) {//如果集合为空或者undefined或者其他假值,返回集合
      return collection;
    }
    if (!isArrayLike(collection)) {//如果集合不是数组(是对象),调用eachFunc并将结果返回
      return eachFunc(collection, iteratee);
    }
    var length = collection.length,//集合长度
        index = fromRight ? length : -1,//集合索引
        iterable = Object(collection);//将collection转为对象(比如说collection是一个字符串)
    //遍历,调用遍历器,如果返回false,跳出循环
    while ((fromRight ? index-- : ++index < length)) {
      if (iteratee(iterable[index], index, iterable) === false) {
        break;
      }
    }
    return collection;//返回集合
  };
}

module.exports = createBaseEach;

each

//each.js

module.exports = require('./forEach');

_.forEachRight(collection, [iteratee=_.identity])/_.eachRight(collection, [iteratee=_.identity])

 这个方法和_.forEach很像,除了它是从右边向左开始迭代

依赖于arrayEachRight和baseEachRight方法

arrayEachRight

//arrayEachRight.js

/**
 * _.forEachRight的特殊版本,不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要遍历的数组.
 * @param {Function} iteratee 每次迭代调用的方法.
 * @returns {Array} 返回这个数组.
 */
function arrayEachRight(array, iteratee) {//基本上和arrayEach方法相同,除了是从右边开始遍历
  var length = array == null ? 0 : array.length;

  while (length--) {
    if (iteratee(array[length], length, array) === false) {
      break;
    }
  }
  return array;
}

module.exports = arrayEachRight;

baseEachRight

//_baseEachRight.js

var baseForOwnRight = require('./_baseForOwnRight'),//遍历本身可枚举属性的方法(baseForOwn(object, iteratee)),但是是从最后的属性开始遍历
    createBaseEach = require('./_createBaseEach');//createBaseEach方法

/**
 * _.forEachRight的基本实现,不支持遍历器的简写
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} iteratee 每次迭代调用的方法.
 * @returns {Array|Object} 返回这个集合.
 */
var baseEachRight = createBaseEach(baseForOwnRight, true);//调用createBaseEach方法,传入eachFunc参数为baseForOwnRight,并且从右边开始遍历

module.exports = baseEachRight;

再看forEachRight方法源码

//forEachRight.js

var arrayEachRight = require('./_arrayEachRight'),//arrayEachRight方法
    baseEachRight = require('./_baseEachRight'),//baseEachRight方法
    castFunction = require('./_castFunction'),//创建函数
    isArray = require('./isArray');//是否是数组

/**
 *
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 每次迭代调用的方法.
 * @returns {Array|Object} 返回这个集合.
 * @example
 *
 * _.forEachRight([1, 2], function(value) {
 *   console.log(value);
 * });
 * // => Logs `2` then `1`.
 */
function forEachRight(collection, iteratee) {
  var func = isArray(collection) ? arrayEachRight : baseEachRight;//如果是数组调用arrayEachRight,否则调用aseEachRight
  return func(collection, castFunction(iteratee));//调用func并将结果作为返回值返回。
}

module.exports = forEachRight;

eachRight

//eachRight.js

module.exports = require('./forEachRight');

_.every(collection, [predicate=_.identity])

判断集合中所有元素都能通过判断条件,如果有一次遍历返回false,则停止遍历,遍历器接受三个参数(value, index|key, collection)

这个方法依赖于arrayEvery和baseEvery方法

arrayEvery

//_arrayEvery.js

/**
 * _.every针对数组的特殊版本,不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要迭代的数组.
 * @param {Function} predicate 每次迭代调用的方法.
 * @returns {boolean} 如果每个元素都通过判断返回true,否则返回false
 */
function arrayEvery(array, predicate) {
  var index = -1,//数组索引
      length = array == null ? 0 : array.length;//数组长度

  while (++index < length) {//遍历数组,如果当前元素调用判断方法返回false,则返回false
    if (!predicate(array[index], index, array)) {
      return false;
    }
  }
  return true;//都通过了判断,返回true
}

module.exports = arrayEvery;

baseEvery

//_baseEvery.js

var baseEach = require('./_baseEach');//基础遍历方法

/**
 * _.every的基本实现,不支持遍历器的简写.
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} predicate 每次迭代调用的方法.
 * @returns {boolean} 如果所有元素调用判断方法返回true,则返回true,否则返回false
 *  else `false`
 */
function baseEvery(collection, predicate) {
  var result = true;//初始结果为true
  baseEach(collection, function(value, index, collection) {//遍历集合,如果result为false停止遍历
    result = !!predicate(value, index, collection);//调用predicate方法,并且将结果转化为boolean类型
    return result;
  });
  return result;//返回result
}

module.exports = baseEvery;

再看every方法

//every.js

var arrayEvery = require('./_arrayEvery'),//arrayEvery方法
    baseEvery = require('./_baseEvery'),//baseEvery方法
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    isArray = require('./isArray'),//是否是数组
    isIterateeCall = require('./_isIterateeCall');//是否是遍历方法的参数(value,index,array)

/**
 *
 *
 * @param {Array|Object} 需要遍历的集合.
 * @param {Function} [predicate=_.identity] 每次迭代调用的方法.
 * @param- {Object} [guard] 使能作为一个遍历器当做像_.map方法的参数。
 * @returns {boolean} 如果所有元素通过判断则返回true
 *  else `false`.
 * @example
 *
 * _.every([true, 1, null, 'yes'], Boolean);
 * // => false
 *
 * var users = [
 *   { 'user': 'barney', 'age': 36, 'active': false },
 *   { 'user': 'fred',   'age': 40, 'active': false }
 * ];
 *
 * // The `_.matches` iteratee shorthand.
 * _.every(users, { 'user': 'barney', 'active': false });
 * // => false
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.every(users, ['active', false]);
 * // => true
 *
 * // The `_.property` iteratee shorthand.
 * _.every(users, 'active');
 * // => false
 */
function every(collection, predicate, guard) {
  var func = isArray(collection) ? arrayEvery : baseEvery;//如果是数组调用arrayEvery,否则调用baseEvery
  if (guard && isIterateeCall(collection, predicate, guard)) {//如果是遍历器的参数,判断条件为undefined
    predicate = undefined;
  }
  return func(collection, baseIteratee(predicate, 3));//调用func并且将遍历器封装,使之支持简写
}

module.exports = every;

_.filter(collection, [predicate=_.identity])

遍历集合中的所有元素,返回一个数组包含集合中所有通过判断条件返回true的值。判断条件接受三个参数(value, index|key, collection)

这个方法依赖于arrayFilter和baseFilter方法

arrayFilter

//_arrayFilter.js

/**
 * _.filter针对数组的版本,不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要遍历的数组.
 * @param {Function} predicate 每次迭代调用的方法.
 * @returns {Array} 返回一个新的过滤后的数组.
 */
function arrayFilter(array, predicate) {
  var index = -1,//数组索引
      length = array == null ? 0 : array.length,//数组长度
      resIndex = 0,//返回结果的索引
      result = [];//返回结果

  while (++index < length) {//遍历数组
    var value = array[index];//当前元素
    if (predicate(value, index, array)) {//调用判断条件如果返回true,将当前元素添加到result中
      result[resIndex++] = value;
    }
  }
  return result;//返回结果。
}

module.exports = arrayFilter;

baseFilter

//_baseFilter.js

var baseEach = require('./_baseEach');//基础遍历方法

/**
 * _.filter的基本实现,不支持遍历器的简写.
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} predicate 每次迭代调用的方法.
 * @returns {Array} 返回一个新的过滤后的数组.
 */
function baseFilter(collection, predicate) {
  var result = [];//结果数组
  baseEach(collection, function(value, index, collection) {//遍历集合,如果当前值通过遍历条件,添加到结果中。
    if (predicate(value, index, collection)) {
      result.push(value);
    }
  });
  return result;//返回结果数组
}

module.exports = baseFilter;

再看filter方法

//filter.js

var arrayFilter = require('./_arrayFilter'),//arrayFilter方法
    baseFilter = require('./_baseFilter'),//baseFilter方法
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    isArray = require('./isArray');//是否为数组

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [predicate=_.identity] 每次迭代调用的判断方法.
 * @returns {Array} 返回一个新的过滤后的数组.
 * @see _.reject
 * @example
 *
 * var users = [
 *   { 'user': 'barney', 'age': 36, 'active': true },
 *   { 'user': 'fred',   'age': 40, 'active': false }
 * ];
 *
 * _.filter(users, function(o) { return !o.active; });
 * // => objects for ['fred']
 *
 * // The `_.matches` iteratee shorthand.
 * _.filter(users, { 'age': 36, 'active': true });
 * // => objects for ['barney']
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.filter(users, ['active', false]);
 * // => objects for ['fred']
 *
 * // The `_.property` iteratee shorthand.
 * _.filter(users, 'active');
 * // => objects for ['barney']
 */
function filter(collection, predicate) {//和forEach类似,不解释。
  var func = isArray(collection) ? arrayFilter : baseFilter;
  return func(collection, baseIteratee(predicate, 3));
}

module.exports = filter;

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

见源码学习(1)

_.findLast(collection, [predicate=_.identity], [fromIndex=collection.length-1])

见源码学习(1)

_.flatMap(collection, [iteratee=_.identity])

对集合通过遍历方法后得到的数组执行扁平化操作,并返回扁平化之后的数组,遍历方法接受三个参数(value, index|key, collection)

这个方法依赖于数组扁平化flatten和map方法,flatten在源码学习(1)中已经分析过,先看看map方法

_.map(collection, [iteratee=_.identity])

 创建一个数组,数组中的值为集合中对应索引得元素调用遍历器之后的值,遍历器接受三个参数* (value, index|key, collection)

这个方法依赖于arrayMap和baseMap

arrayMap

//_arrayMap.js

/**
 * _.map针对数组的特殊版本不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要遍历的数组.
 * @param {Function} iteratee 每次遍历调用的方法.
 * @returns {Array} 返回新的映射后的数组.
 */
function arrayMap(array, iteratee) {
  var index = -1,//数组索引
      length = array == null ? 0 : array.length,//数组长度
      result = Array(length);//返回结果

  while (++index < length) {//遍历数组
    result[index] = iteratee(array[index], index, array);//结果中对应的值为当前元素调用遍历器之后的返回值
  }
  return result;//返回结果数组
}

module.exports = arrayMap;

baseMap

//_baseMap.js

var baseEach = require('./_baseEach'),//基础遍历方法
    isArrayLike = require('./isArrayLike');//是否为数组

/**
 * _.map的基本实现,不支持遍历器的简写
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} iteratee 每次迭代调用的方法.
 * @returns {Array} 返回新的映射后的数组.
 */
function baseMap(collection, iteratee) {
  var index = -1,//集合索引
      result = isArrayLike(collection) ? Array(collection.length) : [];//返回结果

  baseEach(collection, function(value, key, collection) {//调用baseEach方法,将结果中对应的值设置为为当前元素调用遍历器之后的返回值
    result[++index] = iteratee(value, key, collection);
  });
  return result;//返回结果
}

module.exports = baseMap;

map.js

//map.js

var arrayMap = require('./_arrayMap'),//arrayMap方法
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseMap = require('./_baseMap'),//baseMap方法
    isArray = require('./isArray');//是否为数组

/**
 *
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 每次遍历调用的方法.
 * @returns {Array} 返回新的映射后的数组.
 * @example
 *
 * function square(n) {
 *   return n * n;
 * }
 *
 * _.map([4, 8], square);
 * // => [16, 64]
 *
 * _.map({ 'a': 4, 'b': 8 }, square);
 * // => [16, 64] (iteration order is not guaranteed)
 *
 * var users = [
 *   { 'user': 'barney' },
 *   { 'user': 'fred' }
 * ];
 *
 * // The `_.property` iteratee shorthand.
 * _.map(users, 'user');
 * // => ['barney', 'fred']
 */
function map(collection, iteratee) {
  var func = isArray(collection) ? arrayMap : baseMap;//如果是数组调用arrayMap,否则调用baseMap
  return func(collection, baseIteratee(iteratee, 3));//调用func,并且封装遍历器,将结果作为返回值返回
}

module.exports = map;

回过头来再看flatMap

//flatMap.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化方法(见源码学习(1))
    map = require('./map');//map方法

/**
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity]每次迭代调用的方法.
 * @returns {Array} 返回新的扁平化后的数组.
 * @example
 *
 * function duplicate(n) {
 *   return [n, n];
 * }
 *
 * _.flatMap([1, 2], duplicate);
 * // => [1, 1, 2, 2]
 */
function flatMap(collection, iteratee) {
  //先调用map方法得到结果数组,并且对数组调用baseFlatten方法,执行一级变扁平化操作,并且将结果返回
  return baseFlatten(map(collection, iteratee), 1);
}

module.exports = flatMap;

_.flatMapDeep(collection, [iteratee=_.identity])

和_.flatMap很像,除了它递归的执行扁平化,直到不能执行

//flatMapDeep.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化方法(见源码学习(1))
    map = require('./map');//map方法

var INFINITY = 1 / 0;//无限大的值

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 每次迭代调用的方法.
 * @returns {Array} 返回新的扁平化后的数组.
 * @example
 *
 * function duplicate(n) {
 *   return [[[n, n]]];
 * }
 *
 * _.flatMapDeep([1, 2], duplicate);
 * // => [1, 1, 2, 2]
 */
function flatMapDeep(collection, iteratee) {//和flatMap很像,只不过扁平化无限次
  return baseFlatten(map(collection, iteratee), INFINITY);
}

module.exports = flatMapDeep;

_.flatMapDepth(collection, [iteratee=_.identity], [depth=1])

这个方法和_.flatMap很像,除了它可以指定执行扁平化操作的次数

//flatMapDepth.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化方法(见源码学习(1))
    map = require('./map'),//map方法
    toInteger = require('./toInteger');//转化为整形

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 每次迭代调用的方法.
 * @param {number} [depth=1] 递归执行扁平化操作的次数.
 * @returns {Array} Returns the new flattened array.
 * @example
 *
 * function duplicate(n) {
 *   return [[[n, n]]];
 * }
 *
 * _.flatMapDepth([1, 2], duplicate, 2);
 * // => [[1, 1], [2, 2]]
 */
function flatMapDepth(collection, iteratee, depth) {//和flatMap很像,只不过可以指定扁平化的次数
  depth = depth === undefined ? 1 : toInteger(depth);
  return baseFlatten(map(collection, iteratee), depth);
}

module.exports = flatMapDepth;

今天先到这里,一步一个脚印~~~

 

posted @ 2017-07-08 00:32  天下大雨  阅读(862)  评论(0编辑  收藏  举报