继续学习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;
今天先到这里,一步一个脚印~~~