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

 

posted @ 2021-09-09 16:33  雪之下。  阅读(1676)  评论(0)    收藏  举报