zoukankan      html  css  js  c++  java
  • 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;

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

  • 相关阅读:
    Longest Palindromic Substring
    PayPal MLSE job description
    Continuous Median
    Remove Duplicates From Linked List
    Valid IP Address
    Longest substring without duplication
    Largest range
    Subarray sort
    Multi String Search
    Suffix Trie Construction
  • 原文地址:https://www.cnblogs.com/wandiao/p/7134838.html
Copyright © 2011-2022 走看看