• 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;

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

  • 相关阅读:
    02 基本介绍
    01 概述 网络分层
    04 可扩展
    Java 注解2
    03 高可用
    重拾安卓_00_资源帖
    JavaUtil_09_通用工具类-01_Hutool
    java支付宝开发-01-沙箱环境接入
    java支付宝开发-00-资源帖
    svn_学习_01_TortoiseSVN使用教程
  • 原文地址:https://www.cnblogs.com/wandiao/p/7134838.html
Copyright © 2020-2023  润新知