JS: _countBy()函数
_.countBy(collection, [iteratee=_.identity])
_countBy创建一个对象,对数组或者对象的每个元素或属性调用iteratee迭代器后生成这个对象的键,键的值是这个键出现的次数
iteratee支持传递属性名或者属性路径
参数
collection (Array|Object): 需要遍历的集合
[iteratee=_.identity] (Function): 转变键值的遍历器
返回值
(Object): 返回存储键累计值的对象
示例
1 _.countBy([6.1, 4.2, 6.3], Math.floor); 2 // => { '4': 1, '6': 2 } 3 4 // The `_.property` iteratee shorthand. 5 _.countBy(['one', 'two', 'three'], 'length'); 6 // => { '3': 2, '5': 1 }
源码
1 import baseAssignValue from './.internal/baseAssignValue.js' 2 import reduce from './reduce.js' 3 4 /** Used to check objects for own properties. */ 5 const hasOwnProperty = Object.prototype.hasOwnProperty 6 7 /** 8 * Creates an object composed of keys generated from the results of running 9 * each element of `collection` thru `iteratee`. The corresponding value of 10 * each key is the number of times the key was returned by `iteratee`. The 11 * iteratee is invoked with one argument: (value). 12 * 13 * @since 0.5.0 14 * @category Collection 15 * @param {Array|Object} collection The collection to iterate over. 16 * @param {Function} iteratee The iteratee to transform keys. 17 * @returns {Object} Returns the composed aggregate object. 18 * @example 19 * 20 * const users = [ 21 * { 'user': 'barney', 'active': true }, 22 * { 'user': 'betty', 'active': true }, 23 * { 'user': 'fred', 'active': false } 24 * ] 25 * 26 * countBy(users, 'active'); 27 * // => { 'true': 2, 'false': 1 } 28 */ 29 //创建一个对象,对数组或者对象的每个元素或属性调用iteratee迭代器后生成这个对象的键,键的值是这个键出现的次数 30 //iteratee支持传递属性名或者属性路径 31 function countBy(collection, iteratee) { 32 return reduce(collection, (result, value, key) => {//调用reduce累加器 33 key = iteratee(value) 34 if (hasOwnProperty.call(result, key)) {//如果结果对象上已经有当前key,key对应的值累加1 35 ++result[key] 36 } else {//如果结果对象上没有当前key,就用baseAssignValue给结果对象上新增key,值为1 37 baseAssignValue(result, key, 1) 38 } 39 return result 40 }, {}) 41 } 42 43 export default countBy
baseAssignValue
1 /** 2 * The base implementation of `assignValue` and `assignMergeValue` without 3 * value checks. 4 * 5 * @private 6 * @param {Object} object The object to modify. 7 * @param {string} key The key of the property to assign. 8 * @param {*} value The value to assign. 9 */ 10 //assignValue和assignMergeValue的基础实现 11 function baseAssignValue(object, key, value) { 12 if (key == '__proto__') {//如果key是__proto__,就用Object.defineProperty设置 13 Object.defineProperty(object, key, { 14 'configurable': true, 15 'enumerable': true, 16 'value': value, 17 'writable': true 18 }) 19 } else {//否则直接设置 20 object[key] = value 21 } 22 } 23 24 export default baseAssignValue
reduce
1 import arrayReduce from './.internal/arrayReduce.js' 2 import baseEach from './.internal/baseEach.js' 3 import baseReduce from './.internal/baseReduce.js' 4 5 /** 6 * Reduces `collection` to a value which is the accumulated result of running 7 * each element in `collection` thru `iteratee`, where each successive 8 * invocation is supplied the return value of the previous. If `accumulator` 9 * is not given, the first element of `collection` is used as the initial 10 * value. The iteratee is invoked with four arguments: 11 * (accumulator, value, index|key, collection). 12 * 13 * Many lodash methods are guarded to work as iteratees for methods like 14 * `reduce`, `reduceRight`, and `transform`. 15 * 16 * The guarded methods are: 17 * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, 18 * and `sortBy` 19 * 20 * @since 0.1.0 21 * @category Collection 22 * @param {Array|Object} collection The collection to iterate over. 23 * @param {Function} iteratee The function invoked per iteration. 24 * @param {*} [accumulator] The initial value. 25 * @returns {*} Returns the accumulated value. 26 * @see reduceRight, transform 27 * @example 28 * 29 * reduce([1, 2], (sum, n) => sum + n, 0) 30 * // => 3 31 * 32 * reduce({ 'a': 1, 'b': 2, 'c': 1 }, (result, value, key) => { 33 * (result[value] || (result[value] = [])).push(key) 34 * return result 35 * }, {}) 36 * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) 37 */ 38 //将每一个集合中的元素通过iteratee处理后的结果累加到一个值,每一次连续的调用的累加值都是上一次的返回值。如果初始累加值没有提供,就使用第一次循环的返回值 39 function reduce(collection, iteratee, accumulator) { 40 const func = Array.isArray(collection) ? arrayReduce : baseReduce//判断collection参数是数组还是其他类型,如果是数组调用arrayReduce,否则baseReduce 41 const initAccum = arguments.length < 3 42 return func(collection, iteratee, accumulator, initAccum, baseEach) 43 } 44 45 export default reduce
arrayReduce
1 /** 2 * A specialized version of `reduce` for arrays. 3 * 4 * @private 5 * @param {Array} [array] The array to iterate over. 6 * @param {Function} iteratee The function invoked per iteration. 7 * @param {*} [accumulator] The initial value. 8 * @param {boolean} [initAccum] Specify using the first element of `array` as 9 * the initial value. 10 * @returns {*} Returns the accumulated value. 11 */ 12 //为数组类型数据提供的reduce方法 13 function arrayReduce(array, iteratee, accumulator, initAccum) { 14 let index = -1//循环索引 15 const length = array == null ? 0 : array.length//数组长度 16 17 if (initAccum && length) {//如果没有提供累加器初始值,且数组至少有一个元素,累加器初始值就是数组第一个元素 18 accumulator = array[++index] 19 } 20 while (++index < length) {//循环累加 21 accumulator = iteratee(accumulator, array[index], index, array) 22 } 23 return accumulator 24 } 25 26 export default arrayReduce
baseReduce
1 /** 2 * The base implementation of `reduce` and `reduceRight` which iterates 3 * over `collection` using `eachFunc`. 4 * 5 * @private 6 * @param {Array|Object} collection The collection to iterate over. 7 * @param {Function} iteratee The function invoked per iteration. 8 * @param {*} accumulator The initial value. 9 * @param {boolean} initAccum Specify using the first or last element of 10 * `collection` as the initial value. 11 * @param {Function} eachFunc The function to iterate over `collection`. 12 * @returns {*} Returns the accumulated value. 13 */ 14 //reduce基础实现,使用eachFunc方法执行累加的方法 15 function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { 16 eachFunc(collection, (value, index, collection) => { 17 accumulator = initAccum 18 ? (initAccum = false, value) 19 : iteratee(accumulator, value, index, collection) 20 //如果没有提供累加初始值,就用第一个元素作为初始值 21 }) 22 return accumulator 23 } 24 25 export default baseReduce
baseEach
1 import baseForOwn from './baseForOwn.js' 2 import isArrayLike from '../isArrayLike.js' 3 4 /** 5 * The base implementation of `forEach`. 6 * 7 * @private 8 * @param {Array|Object} collection The collection to iterate over. 9 * @param {Function} iteratee The function invoked per iteration. 10 * @returns {Array|Object} Returns `collection`. 11 */ 12 //forEach的基础实现 13 //collection被迭代遍历的对象,iteratee遍历器 14 function baseEach(collection, iteratee) { 15 if (collection == null) {//如果collection为空,直接返回原对象 16 return collection 17 } 18 if (!isArrayLike(collection)) {//如果collection不是array-like对象,就调用baseForOwn处理 19 return baseForOwn(collection, iteratee) 20 } 21 const length = collection.length//对象长度 22 const iterable = Object(collection) 23 let index = -1//循环索引 24 25 while (++index < length) {//循环调用iteratee方法 26 if (iteratee(iterable[index], index, iterable) === false) { 27 break 28 } 29 } 30 return collection 31 } 32 33 export default baseEach

#
浙公网安备 33010602011771号