lodash源码学习(6)

继续集合篇。

“Collection” Methods

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

创建一个对象,它的key值为集合中的所有元素调用iteratee之后的不同值,每个key相应的value是一个数组包含所有原先集合中生成这个key的值。遍历器接受一个参数(value)

//groupBy.js

var baseAssignValue = require('./_baseAssignValue'),//基础赋值方法(见源码学习(5))
    createAggregator = require('./_createAggregator');//创建聚合函数(见源码学习(5))

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

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

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

module.exports = groupBy;

_.includes(collection, value, [fromIndex=0])

检查value是否在集合中,如果集合是一个字符串,检查value是不是字符串的一个 片段,否则使用SameValueZero的方式比较(全等比较),如果fromIndex为负值,从末尾开始计算

//includes.js

var baseIndexOf = require('./_baseIndexOf'),//获取value在数组 array所在的索引值(见源码学习(2))
    isArrayLike = require('./isArrayLike'),//是否是类似数组
    isString = require('./isString'),//是否是字符串
    toInteger = require('./toInteger'),//转化为整形
    values = require('./values');//得到一个数组,包含对象中自身所有可枚举的属性的值

var nativeMax = Math.max;//原生最大值方法

/**
 * 
 *
 * @param {Array|Object|string} collection 需要处理的集合.
 * @param {*} value 需要查找的值.
 * @param {number} [fromIndex=0] 查找的开始位置.
 * @param- {Object} [guard] 使这个方法能够作为一个遍历参数被像_.reduce这样的方法调用
 * @returns {boolean} 如果集合中有value,返回true,否则返回false.
 * @example
 *
 * _.includes([1, 2, 3], 1);
 * // => true
 *
 * _.includes([1, 2, 3], 1, 2);
 * // => false
 *
 * _.includes({ 'a': 1, 'b': 2 }, 1);
 * // => true
 *
 * _.includes('abcd', 'bc');
 * // => true
 */
function includes(collection, value, fromIndex, guard) {
  collection = isArrayLike(collection) ? collection : values(collection);//如果是类似数组,得到这个数组,否则得到这个对象的所有值
  fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;//将fromIndex转换为整形

  var length = collection.length;//集合长度
  if (fromIndex < 0) {//小于0,从末尾计算
    fromIndex = nativeMax(length + fromIndex, 0);
  }
  return isString(collection) //如果是字符串使用字符串的indexOf方法判断是否含有value,否则调用baseIndexOf判断集合中是否含有value
    ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
    : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
}

module.exports = includes;

_.invokeMap(collection, path, [args])

对集合中的每个元素调用path参数的方法,遍历方法接受任务参数,如果path是一个方法,则绑定this(当前元素)

//invokeMap.js


var apply = require('./_apply'),//同Function.apply
    baseEach = require('./_baseEach'),//基础遍历方法(见源码学习(5))
    baseInvoke = require('./_baseInvoke'),//基础调用方法(var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] } => _.invoke(object, 'a[0].b.c.slice', 1, 3) => [2, 3]),暂不分析
    baseRest = require('./_baseRest'),//创建具有rest参数的方法。
    isArrayLike = require('./isArrayLike');//是否是类似数组

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Array|Function|string} path 每次遍历需要调用的方法.
 * @param {...*} [args] 调用方法的参数.
 * @returns {Array} 返回包含每个结果的数组.
 * @example
 *
 * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
 * // => [[1, 5, 7], [1, 2, 3]]
 *
 * _.invokeMap([123, 456], String.prototype.split, '');
 * // => [['1', '2', '3'], ['4', '5', '6']]
 */
var invokeMap = baseRest(function(collection, path, args) {//创建rest参数
  var index = -1,//集合索引
      isFunc = typeof path == 'function',//path参数是否为函数
      result = isArrayLike(collection) ? Array(collection.length) : [];//结果数组

  baseEach(collection, function(value) {//遍历集合,如果path是方法,对value调用该方法并传入args,
      //否则调用baseInvoke方法。
    result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
  });
  return result;//返回结果数组
});

module.exports = invokeMap;    

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

创建一个对象,生成的key值为集合中的每个元素通过遍历器之后的返回值,相应的value为生成key的最后一个元素,遍历器接受一个参数(value)

//keyBy.js

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

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 转换key的遍历方法.
 * @returns {Object} 返回组合的聚合对象.
 * @example
 *
 * var array = [
 *   { 'dir': 'left', 'code': 97 },
 *   { 'dir': 'right', 'code': 100 }
 * ];
 *
 * _.keyBy(array, function(o) {
 *   return String.fromCharCode(o.code);
 * });
 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
 *
 * _.keyBy(array, 'dir');
 * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
 */
var keyBy = createAggregator(function(result, value, key) {//创建聚合函数,传入setter
  baseAssignValue(result, key, value);//对对象进行赋值
});

module.exports = keyBy;

_.orderBy(collection, [iteratees=[_.identity]], [orders])

这个方法和_.sortBy很像,除了它允许指定每个遍历器的排序方式,如果没有指定orders,默认使用升序排列。传入desc表示降序,传入asc表示升序。

orderBy方法依赖于baseOrderBy方法,而baseOrderBy方法主要依赖于compareMultiple和baseSortBy方法,源码如下

baseSortBy

//_baseSortBy.js

/**
 * _.sortBy的基本实现,用compare定义比较规则,然后将每个元素的值变为每个元素的value属性
 *
 * @private
 * @param {Array} array 需要排序的数组.
 * @param {Function} comparer 定义排序规则的方法.
 * @returns {Array} 返回这个数组.
 */
function baseSortBy(array, comparer) {
  var length = array.length;
  array.sort(comparer);//排序
  while (length--) {
    array[length] = array[length].value;//赋值
  }
  return array;

}
module.exports = baseSortBy;

compareMultiple

//_compareMultiple.js

var compareAscending = require('./_compareAscending');//常规大小比较方法,升序

/**
 * 
 *被_orderBy调用,用于比较一个对象的多个属性,并对它们进行排序
 *
 * @private
 * @param {Object} object 需要比较的对象.
 * @param {Object} other 被比较的对象.
 * @param {boolean[]|string[]} orders 每个属性的排序规则.
 * @returns {number} 返回排序标识(正为升序,负为降序).
 */
function compareMultiple(object, other, orders) {
  var index = -1,//属性索引
      objCriteria = object.criteria,//调用遍历器之后的属性值
      othCriteria = other.criteria,//被比较的属性值
      length = objCriteria.length,//属性长度
      ordersLength = orders.length;//排序方式的长度

  while (++index < length) {//遍历criteria
    var result = compareAscending(objCriteria[index], othCriteria[index]);//比较对应的属性
    if (result) {//如果不相等
      if (index >= ordersLength) {//如果当前属性值索引比orders长度长(并没有这个属性的排序方式)
        return result;//返回升序
      }
      var order = orders[index];//当前属性的排序方式
      return result * (order == 'desc' ? -1 : 1);//如果排序方式为desc,result为降序,否则为升序
    }
  }
  
  return object.index - other.index;//如果相等,直接比较object和other的index属性
}

module.exports = compareMultiple;

再看baseOrderBy方法

//_baseOrderBy.js

var arrayMap = require('./_arrayMap'),//同Array.map(见源码学习(5))
    baseIteratee = require('./_baseIteratee'),//遍历器封装,支持属性简写
    baseMap = require('./_baseMap'),//基础map方法(见源码学习(5))
    baseSortBy = require('./_baseSortBy'),//baseSortBy方法
    baseUnary = require('./_baseUnary'),//创建只有一个参数的方法
    compareMultiple = require('./_compareMultiple'),//多个属性的排序
    identity = require('./identity');//返回函数的第一个参数

/**
 * _.orderBy的基本实现,没有guards参数
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function[]|Object[]|string[]} iteratees 用于排序的遍历器.
 * @param {string[]} orders 每个遍历器的排序规则.
 * @returns {Array} 返回新的排序后的数组.
 */
function baseOrderBy(collection, iteratees, orders) {
  var index = -1;//集合索引
  iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(baseIteratee));//封装所有遍历器

  var result = baseMap(collection, function(value, key, collection) {//遍历集合
    var criteria = arrayMap(iteratees, function(iteratee) {
      return iteratee(value);//对集合中的元素调用所有的遍历器,得到criteria
    });
    return { 'criteria': criteria, 'index': ++index, 'value': value };//返回含有几个属性的一个对象
  });

  return baseSortBy(result, function(object, other) {//对result进行排序,调用compareMultiple方法,并将结果返回
    return compareMultiple(object, other, orders);
  });
}

module.exports = baseOrderBy;

orderBy

//orderBy.js

var baseOrderBy = require('./_baseOrderBy'),//baseOrderBy方法
    isArray = require('./isArray');//是否是数组

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Array[]|Function[]|Object[]|string[]} 遍历器,用于排序的依赖
 *  The iteratees to sort by.
 * @param {string[]} [orders] 每个遍历器对应的排序规则.
 * @param- {Object} [guard] 能够作为像_.reduce这样的方法的参数
 * @returns {Array} 返回排序之后的数组.
 * @example
 *
 * var users = [
 *   { 'user': 'fred',   'age': 48 },
 *   { 'user': 'barney', 'age': 34 },
 *   { 'user': 'fred',   'age': 40 },
 *   { 'user': 'barney', 'age': 36 }
 * ];
 *
 * // Sort by `user` in ascending order and by `age` in descending order.
 * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
 * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
 */
function orderBy(collection, iteratees, orders, guard) {
  if (collection == null) {//如果集合为空
    return [];//返回空数组
  }
  if (!isArray(iteratees)) {//如果遍历器不是数组,转化为数组
    iteratees = iteratees == null ? [] : [iteratees];
  }
  orders = guard ? undefined : orders;
  if (!isArray(orders)) {//如果排序方法不是数组,转化为数组
    orders = orders == null ? [] : [orders];
  }
  return baseOrderBy(collection, iteratees, orders);//调用baseOrderBy并将结果作为返回值返回
}

module.exports = orderBy;

_.sortBy(collection, [iteratees=[_.identity]])

对集合中的每个元素调用每个遍历器得到对应结果,然后进行升序排序,得打排序之后的数组。遍历器接收一个参数(value)

//sortBy.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化方法
    baseOrderBy = require('./_baseOrderBy'),//baseOrderBy方法
    baseRest = require('./_baseRest'),//创建具有rest参数的方法
    isIterateeCall = require('./_isIterateeCall');//是否是遍历器的参数

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {...(Function|Function[])} [iteratees=[_.identity]] 用于分类的遍历器
 * @returns {Array} 返回排序之后的数组.
 * @example
 *
 * var users = [
 *   { 'user': 'fred',   'age': 48 },
 *   { 'user': 'barney', 'age': 36 },
 *   { 'user': 'fred',   'age': 40 },
 *   { 'user': 'barney', 'age': 34 }
 * ];
 *
 * _.sortBy(users, [function(o) { return o.user; }]);
 * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
 *
 * _.sortBy(users, ['user', 'age']);
 * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
 */
var sortBy = baseRest(function(collection, iteratees) {//创建rest参数形式的iteratees
  if (collection == null) {//如果集合为空,返回空数组
    return [];
  }
  var length = iteratees.length;
  if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {//如果是遍历方法的参数,遍历器为空
    iteratees = [];
  } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {//如果前三个用于排序的方法为遍历器的参数
    iteratees = [iteratees[0]];//遍历器为第一个遍历器。
  }
  return baseOrderBy(collection, baseFlatten(iteratees, 1), []);//调用baseOrderBy,并且将iteratees展开一级,然后将结果作为返回值返回。
});

module.exports = sortBy;

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

创建一个数组包含两个分组,第一个分组包含所有调用判断条件返回true的值,第二个分组包含返回false的值,判断条件接受一个参数(value)

//partition.js

var createAggregator = require('./_createAggregator');//创建聚合函数,见源码学习(5)

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [predicate=_.identity] 每次迭代调用的方法.
 * @returns {Array} 返回分组的数组.
 * @example
 *
 * var users = [
 *   { 'user': 'barney',  'age': 36, 'active': false },
 *   { 'user': 'fred',    'age': 40, 'active': true },
 *   { 'user': 'pebbles', 'age': 1,  'active': false }
 * ];
 *
 * _.partition(users, function(o) { return o.active; });
 * // => objects for [['fred'], ['barney', 'pebbles']]
 *
 * // The `_.matches` iteratee shorthand.
 * _.partition(users, { 'age': 1, 'active': false });
 * // => objects for [['pebbles'], ['barney', 'fred']]
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.partition(users, ['active', false]);
 * // => objects for [['barney', 'pebbles'], ['fred']]
 *
 * // The `_.property` iteratee shorthand.
 * _.partition(users, 'active');
 * // => objects for [['fred'], ['barney', 'pebbles']]
 */
var partition = createAggregator(function(result, value, key) {//创建聚合函数,传入setter,传入初始化结果为[[], []]
  result[key ? 0 : 1].push(value);//如果key值为true,将value传入result[0],否则传入result[1]
}, function() { return [[], []]; });

module.exports = partition;

_.reduce(collection, [iteratee=_.identity], [accumulator])

 减少集合为集合中每个元素调用遍历方法之后累加的值,每次调用的返回值作为下一次调用的第一个参数,如果初始值不存在,默认将集合中第一个元素作为初始值。遍历器接受4个参数(accumulator, value, index|key, collection).

这个方法依赖于arrayReduce和baseReduce方法

arrayReduce

//_arrayReduce.js

/**
 * _.reduce的特殊版本针对于数组,不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要遍历的数组.
 * @param {Function} iteratee 每次遍历调用的方法.
 * @param {*} [accumulator] 初始值.
 * @param {boolean} [initAccum] 指定是否将数组第一个元素作为初始值.
 * @returns {*} Returns the accumulated value.
 */
function arrayReduce(array, iteratee, accumulator, initAccum) {
  var index = -1,//数组索引
      length = array == null ? 0 : array.length;//数组长度

  if (initAccum && length) {//如果指定initAccum
    accumulator = array[++index];//初始值为array[0]
  }
  while (++index < length) {//遍历数组
    accumulator = iteratee(accumulator, array[index], index, array);//调用遍历器,每次将得到的accumulator传入。
  }
  return accumulator;//返回累计的值
}

module.exports = arrayReduce;

baseReduce

//_baseReduce.js

/**
 * _.reduce和_.reduceRight的基本实现, 不支持遍历器的简写,通过eachFunc遍历集合
 *
 * @private
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} iteratee 每次遍历调用的方法.
 * @param {*} accumulator 初始值.
 * @param {boolean} initAccum 指定是否将数组的第一个元素作为初始值.
 * @param {Function} eachFunc 遍历集合的方法.
 * @returns {*} 返回累加后的值.
 */
function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
  eachFunc(collection, function(value, index, collection) {//遍历集合
    accumulator = initAccum //如果有initAccum,初始值为当前value,并且将initAccum设为false
      ? (initAccum = false, value) 
      : iteratee(accumulator, value, index, collection);//否则accumulator的值为调用iteratee之后的值
  });
  return accumulator;//返回累计的值
}

module.exports = baseReduce;

再看reduce方法源码

//reduce.js

var arrayReduce = require('./_arrayReduce'),//数组reduce方法
    baseEach = require('./_baseEach'),//基础遍历方法,见源码学习(5)
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseReduce = require('./_baseReduce'),//基础reduce方法
    isArray = require('./isArray');//是否是数组

/**
 *
 *
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 每次遍历调用的方法.
 * @param {*} [accumulator] 初始值.
 * @returns {*} 返回累加的值.
 * @example
 *
 * _.reduce([1, 2], function(sum, n) {
 *   return sum + n;
 * }, 0);
 * // => 3
 *
 * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
 *   (result[value] || (result[value] = [])).push(key);
 *   return result;
 * }, {});
 * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
 */
function reduce(collection, iteratee, accumulator) {
  var func = isArray(collection) ? arrayReduce : baseReduce,//如果为数组调用arrayReduce否则为调用baseReduce
      initAccum = arguments.length < 3;//如果参数个数小于3,initAccum为false

  return func(collection, baseIteratee(iteratee, 4), accumulator, initAccum, baseEach);//调用func,传入遍历方法为baseEach,并将结果作为返回值返回
}

module.exports = reduce;

_.reduceRight(collection, [iteratee=_.identity], [accumulator])

和_.reduce很像,除了它是从右向左遍历

这个方法依赖于arrayReduceRight方法和baseEachRight方法,baseEachRight方法在上一次已经分析过,所以只需要看arrayReduceRight

arrayReduceRight

//_arrayReduceRight.js

/**
 * _.reduceRight针对数组的特殊版本,不支持遍历器的简写
 *
 * @private
 * @param {Array} [array] 需要遍历的数组.
 * @param {Function} iteratee 每次遍历调用的方法.
 * @param {*} [accumulator] 初始值.
 * @param {boolean} [initAccum] 指定是否将数组的第一个元素作为初始值.
 * @returns {*} 返回累加的值.
 */
function arrayReduceRight(array, iteratee, accumulator, initAccum) {//和arrayReduce很像
  var length = array == null ? 0 : array.length;
  if (initAccum && length) {
    accumulator = array[--length];//初始值为最后一个元素
  }
  while (length--) {//从最后遍历
    accumulator = iteratee(accumulator, array[length], length, array);
  }
  return accumulator;
}

module.exports = arrayReduceRight;

再看reduceRight源码

//reduceRight.js

var arrayReduceRight = require('./_arrayReduceRight'),//arrayReduceRight方法
    i = require('./_baseEachRight'),//基础each方法,见源码学习(5)
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseReduce = require('./_baseReduce'),//基础reduce方法
    isArray = require('./isArray');//是否是数组

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [iteratee=_.identity] 每次遍历调用的方法.
 * @param {*} [accumulator] 初始值.
 * @returns {*} 返回累加的值.
 * @example
 *
 * var array = [[0, 1], [2, 3], [4, 5]];
 *
 * _.reduceRight(array, function(flattened, other) {
 *   return flattened.concat(other);
 * }, []);
 * // => [4, 5, 2, 3, 0, 1]
 */
function reduceRight(collection, iteratee, accumulator) {
  var func = isArray(collection) ? arrayReduceRight : baseReduce,//如果是数组调用arrayReduceRight,否则调用baseReduce
      initAccum = arguments.length < 3;//如果参数小于3,initAccum为true

  return func(collection, baseIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);//调用func,传入遍历方法为baseEachRight,并将结果作为返回值返回。
}

module.exports = reduceRight;

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

 和_.filter相反,这个方法返回数组中的元素通过判断条件不为true的所有元素。

//reject.js

var arrayFilter = require('./_arrayFilter'),//同Array.filter,见源码学习(5)
    baseFilter = require('./_baseFilter'),//基础filter方法,见源码学习(5)
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    isArray = require('./isArray'),//是否是数组
    negate = require('./negate');//判断反向

/**
 *
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Collection
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [predicate=_.identity] 每次遍历调用的方法.
 * @returns {Array} 返回过滤后的数组.
 * @see _.filter
 * @example
 *
 * var users = [
 *   { 'user': 'barney', 'age': 36, 'active': false },
 *   { 'user': 'fred',   'age': 40, 'active': true }
 * ];
 *
 * _.reject(users, function(o) { return !o.active; });
 * // => objects for ['fred']
 *
 * // The `_.matches` iteratee shorthand.
 * _.reject(users, { 'age': 40, 'active': true });
 * // => objects for ['barney']
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.reject(users, ['active', false]);
 * // => objects for ['fred']
 *
 * // The `_.property` iteratee shorthand.
 * _.reject(users, 'active');
 * // => objects for ['barney']
 */
function reject(collection, predicate) {
  var func = isArray(collection) ? arrayFilter : baseFilter;//如果是数组调用arrayFilter,否则调用baseFilter
  return func(collection, negate(baseIteratee(predicate, 3)));//调用func,并且将判断条件封装,并且反向
}

module.exports = reject;

_.sample(collection)

得到集合中的一个随机元素.

这个方法依赖于arraySample和baseSample方法

arraySample

//_arraySample.js

var baseRandom = require('./_baseRandom');//基础随机方法

/**
 * _.sample针对于数组的特殊版本.
 *
 * @private
 * @param {Array} array 需要取样的数组.
 * @returns {*} 返回随机元素.
 */
function arraySample(array) {
  var length = array.length;//数组长度
  return length ? array[baseRandom(0, length - 1)] : undefined;//如果数组不为空,返回取得随机元素,否则返回undefined
}

module.exports = arraySample;

baseSample

//_baseSample.js

var arraySample = require('./_arraySample'),//数组取样方法
    values = require('./values');//获取对象中每个属性的值

/**
 * _.sample的基本实现
 *
 * @private
 * @param {Array|Object} collection 需要取样的集合.
 * @returns {*} 返回随机元素.
 */
function baseSample(collection) {
  return arraySample(values(collection));//调用arraySample,并传入集合中所有的值。
}

module.exports = baseSample;

sample.js

//sample.js

var arraySample = require('./_arraySample'),//数组取样方法
    baseSample = require('./_baseSample'),//基础取样方法
    isArray = require('./isArray');//是否为数组

/**
 * 
 *
 * @param {Array|Object} 需要取样的集合.
 * @returns {*} 返回这个随机元素.
 * @example
 *
 * _.sample([1, 2, 3, 4]);
 * // => 2
 */
function sample(collection) {//是数组调用arraySample,否则调用baseSample,并且将结果作为返回值返回
  var func = isArray(collection) ? arraySample : baseSample;
  return func(collection);
}

module.exports = sample;

_.shuffle(collection)

创建一个洗牌之后的数组

这个方法依赖于shuffleSelf和baseShuffle方法

shuffleSelf

//_shuffleSelf.js

var baseRandom = require('./_baseRandom');//取得随机数

/**
 * _.shuffle的特殊版本会改变数组和数组长度
 *
 * @private
 * @param {Array} array 需要洗牌的数组.
 * @param {number} [size=array.length] 数组长度.
 * @returns {Array} 返回这个数组.
 */
function shuffleSelf(array, size) {
  var index = -1,//数组索引
      length = array.length,//数组长度
      lastIndex = length - 1;//数组最大索引

  size = size === undefined ? length : size;//如果没传size,则对整个数组洗牌
  while (++index < size) {//遍历数组
    var rand = baseRandom(index, lastIndex),//随机索引
        value = array[rand];//随机值

    array[rand] = array[index];//将随机索引处的元素替换成当前元素
    array[index] = value;//当前元素的值替换成随机元素
  }
  array.length = size;//数组的长度等于size
  return array;//返回这个数组
}

module.exports = shuffleSelf;

baseShuffle

//_baseShuffle.js

var shuffleSelf = require('./_shuffleSelf'),//洗牌方法
    values = require('./values');//取得对象的所有属性的值

/**
 * _.shuffle的基本实现
 *
 * @private
 * @param {Array|Object} collection 需要洗牌的数组.
 * @returns {Array} 返回一个新的重新洗牌之后的数组.
 */
function baseShuffle(collection) {
  return shuffleSelf(values(collection));//调用shuffleSelf,传入集合中的所有的值得数组
}

module.exports = baseShuffle;

再看shuffle方法源码

//shuffle.js

var arrayShuffle = require('./_arrayShuffle'),//数组
    baseShuffle = require('./_baseShuffle'),
    isArray = require('./isArray');

/**
 * 
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Collection
 * @param {Array|Object} collection 需要洗牌的数组.
 * @returns {Array} 返回新的洗牌之后的数组.
 * @example
 *
 * _.shuffle([1, 2, 3, 4]);
 * // => [4, 1, 3, 2]
 */
function shuffle(collection) {//如果是数组调用arrayShuffle,否则调用baseShuffle
  var func = isArray(collection) ? arrayShuffle : baseShuffle;
  return func(collection);
}

module.exports = shuffle;

_.sampleSize(collection, [n=1])

从集合中得到n个随机元素.

这个方法依赖于arraySampleSize和baseSampleSize方法

arraySampleSize

//_arraySampleSize.js

var baseClamp = require('./_baseClamp'),//限制数字大小在给定的返回内 (baseClamp(3,4,5) => 3)
    copyArray = require('./_copyArray'),//复制数组
    shuffleSelf = require('./_shuffleSelf');//洗牌方法

/**
 * _.sampleSize针对数组的特殊版本
 *
 * @private
 * @param {Array} array 需要取样的数组.
 * @param {number} n 需要取样的元素个数.
 * @returns {Array} 返回随机元素的数组.
 */
function arraySampleSize(array, n) {
  return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));//调用shuffleSelf方法,并且限制size
}

module.exports = arraySampleSize;

baseSampleSize

//_baseSampleSize.js

var baseClamp = require('./_baseClamp'),//限制数字大小在给定的返回内
    shuffleSelf = require('./_shuffleSelf'),//洗牌方法
    values = require('./values');//获取所有属性的值

/**
 * _.sampleSize的基本实现,不支持guard参数
 *
 * @private
 * @param {Array|Object} collection 需要取样的集合.
 * @param {number} n 需要取样的元素数量.
 * @returns {Array} 返回包含这些随机元素的数组.
 */
function baseSampleSize(collection, n) {
  var array = values(collection);//获取集合的所有的值
  return shuffleSelf(array, baseClamp(n, 0, array.length));//调用shuffleSelf传入数组长度之间的size
}

module.exports = baseSampleSize;

再看sampleSize本身源码

//sampleSize.js

var arraySampleSize = require('./_arraySampleSize'),//数组取样方法
    baseSampleSize = require('./_baseSampleSize'),//基础取样方法
    isArray = require('./isArray'),//是否是数组
    isIterateeCall = require('./_isIterateeCall'),//是否是遍历器的参数
    toInteger = require('./toInteger');//转化为整型

/**
 * 
 *
 * @param {Array|Object} collection 需要取样的数组.
 * @param {number} [n=1] 需要取样的元素数量.
 * @param- {Object} [guard] 是否可以作为遍历参数被_.map之类的方法调用.
 * @returns {Array} 返回这些随机的元素.
 * @example
 *
 * _.sampleSize([1, 2, 3], 2);
 * // => [3, 1]
 *
 * _.sampleSize([1, 2, 3], 4);
 * // => [2, 3, 1]
 */
function sampleSize(collection, n, guard) {
  if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {//是否是遍历方法的参数或者n是否为undefined
    n = 1;
  } else {
    n = toInteger(n);//将n转为整型
  }
  var func = isArray(collection) ? arraySampleSize : baseSampleSize;//如果是数组调用arraySampleSize,否则调用baseSampleSize
  return func(collection, n);
}

module.exports = sampleSize;

_.size(collection)

得到集合的元素数通过得到集合的长度或者集合中可枚举属性的个数

//size.js

var baseKeys = require('./_baseKeys'),//同Object.keys()
    getTag = require('./_getTag'),//获取数据的类型
    isArrayLike = require('./isArrayLike'),//是否类似数组
    isString = require('./isString'),//是否是字符串
    stringSize = require('./_stringSize');//获取字符串的长度

var mapTag = '[object Map]',//Map类型
    setTag = '[object Set]';//Set类型

/**
 * 
 *
 * @param {Array|Object|string} collection 需要处理的集合.
 * @returns {number} 返回集合的元素数.
 * @example
 *
 * _.size([1, 2, 3]);
 * // => 3
 *
 * _.size({ 'a': 1, 'b': 2 });
 * // => 2
 *
 * _.size('pebbles');
 * // => 7
 */
function size(collection) {
  if (collection == null) {//如果集合为空,返回0
    return 0;
  }
  if (isArrayLike(collection)) {//如果是字符串获取字符串的长度,否则获取集合的长度
    return isString(collection) ? stringSize(collection) : collection.length;
  }
  var tag = getTag(collection);//获取集合的数据类型
  if (tag == mapTag || tag == setTag) {//如果是Set或者Map,返回其size属性
    return collection.size;
  }
  return baseKeys(collection).length;//返回对象可枚举属性的长度。
}

module.exports = size;

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

遍历集合,判断是否有某个元素通过判断条件返回true,如果返回true则终止遍历,判断条件接收三个参数(value, index|key, collection)

这个方法依赖于arraySome和baseSome方法

arraySome

//_arraySome.js

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

  while (++index < length) {//遍历数组,如果当前元素通过判断条件返回true,则返回true
    if (predicate(array[index], index, array)) {
      return true;
    }
  }
  return false;//否则返回false
}

module.exports = arraySome;

baseSome

//_baseSome.js

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

/**
 * _.some的基本实现,不支持遍历器的简写
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} predicate 每次迭代调用的判断条件.
 * @returns {boolean} 如果有任意一个元素通过了判断条件,返回true,否则返回false
 */
function baseSome(collection, predicate) {
  var result;

  baseEach(collection, function(value, index, collection) {//遍历集合
    result = predicate(value, index, collection);//如果判断通过,返回false(不再遍历)
    return !result;
  });
  return !!result;//返回result
}

module.exports = baseSome;

some.js

//some.js

var arraySome = require('./_arraySome'),//数组some方法
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseSome = require('./_baseSome'),//基础some方法
    isArray = require('./isArray'),//是否是数组
    isIterateeCall = require('./_isIterateeCall');//是否是遍历器的参数

/**
 * 
 *
 * @param {Array|Object} collection 需要遍历的集合.
 * @param {Function} [predicate=_.identity] 每次迭代调用的方法.
 * @param- {Object} [guard] 是否能作为遍历参数被_.map这样的方法调用.
 * @returns {boolean} 如果有任意一个元素通过了判断条件,返回true,否则返回false
 * @example
 *
 * _.some([null, 0, 'yes', false], Boolean);
 * // => true
 *
 * var users = [
 *   { 'user': 'barney', 'active': true },
 *   { 'user': 'fred',   'active': false }
 * ];
 *
 * // The `_.matches` iteratee shorthand.
 * _.some(users, { 'user': 'barney', 'active': false });
 * // => false
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.some(users, ['active', false]);
 * // => true
 *
 * // The `_.property` iteratee shorthand.
 * _.some(users, 'active');
 * // => true
 */
function some(collection, predicate, guard) {//如果是数组调用arraySome,否则调用baseSome
  var func = isArray(collection) ? arraySome : baseSome;
  if (guard && isIterateeCall(collection, predicate, guard)) {
    predicate = undefined;
  }
  return func(collection, baseIteratee(predicate, 3));
}

module.exports = some;

至此集合篇,完结了。。,一步一个脚印~~

 

posted @ 2017-07-11 22:10  天下大雨  阅读(1387)  评论(0编辑  收藏  举报