80
_.keyBy(collection, [iteratee=_.identity])
_.keyBy創建一個對象,這個對象的key生成自collection的每一個元素調用iteratee的結果,每一個key對應的value是最后一個負責生成對應key的collection的元素
參數
collection (Array|Object): 需要遍歷的集合
[iteratee=_.identity] (Function): 生成結果數組的key的方法
返回值
(Object): 返回累加好的對象
例子
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 } }
源代碼:
import baseAssignValue from './.internal/baseAssignValue.js' import reduce from './reduce.js' /** * Creates an object composed of keys generated from the results of running * each element of `collection` thru `iteratee`. The corresponding value of * each key is the last element responsible for generating the key. The * iteratee is invoked with one argument: (value). * * @since 4.0.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The iteratee to transform keys. * @returns {Object} Returns the composed aggregate object. * @see groupBy, partition * @example * * const array = [ * { 'dir': 'left', 'code': 97 }, * { 'dir': 'right', 'code': 100 } * ] * * keyBy(array, ({ code }) => String.fromCharCode(code)) * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } */ //創建一個對象,這個對象的key生成自collection的每一個元素調用iteratee的結果,每一個key對應的value是最后一個負責生成對應key的collection的元素 function keyBy(collection, iteratee) { return reduce(collection, (result, value, key) => ( //調用reduce方法,遍歷collection,往累加對象result上累加元素 //key是iteratee的返回值,value是collection當前value baseAssignValue(result, iteratee(value), value), result ), {}) } export default keyBy
baseAssignValue
/** * The base implementation of `assignValue` and `assignMergeValue` without * value checks. * * @private * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ //assignValue和assignMergeValue的基礎實現 function baseAssignValue(object, key, value) { if (key == '__proto__') {//如果key是__proto__,就用Object.defineProperty設置 Object.defineProperty(object, key, { 'configurable': true, 'enumerable': true, 'value': value, 'writable': true }) } else {//否則直接設置 object[key] = value } } export default baseAssignValue
reduce
import arrayReduce from './.internal/arrayReduce.js' import baseEach from './.internal/baseEach.js' import baseReduce from './.internal/baseReduce.js' /** * Reduces `collection` to a value which is the accumulated result of running * each element in `collection` thru `iteratee`, where each successive * invocation is supplied the return value of the previous. If `accumulator` * is not given, the first element of `collection` is used as the initial * value. The iteratee is invoked with four arguments: * (accumulator, value, index|key, collection). * * Many lodash methods are guarded to work as iteratees for methods like * `reduce`, `reduceRight`, and `transform`. * * The guarded methods are: * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, * and `sortBy` * * @since 0.1.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @returns {*} Returns the accumulated value. * @see reduceRight, transform * @example * * reduce([1, 2], (sum, n) => sum + n, 0) * // => 3 * * reduce({ 'a': 1, 'b': 2, 'c': 1 }, (result, value, key) => { * (result[value] || (result[value] = [])).push(key) * return result * }, {}) * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) */ //將每一個集合中的元素通過iteratee處理后的結果累加到一個值,每一次連續的調用的累加值都是上一次的返回值。如果初始累加值沒有提供,就使用第一次循環的返回值 function reduce(collection, iteratee, accumulator) { const func = Array.isArray(collection) ? arrayReduce : baseReduce//判斷collection參數是數組還是其他類型,如果是數組調用arrayReduce,否則baseReduce const initAccum = arguments.length < 3 return func(collection, iteratee, accumulator, initAccum, baseEach) } export default reduce
arrayReduce
/** * A specialized version of `reduce` for arrays. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the first element of `array` as * the initial value. * @returns {*} Returns the accumulated value. */ //為數組類型數據提供的reduce方法 function arrayReduce(array, iteratee, accumulator, initAccum) { let index = -1//循環索引 const length = array == null ? 0 : array.length//數組長度 if (initAccum && length) {//如果沒有提供累加器初始值,且數組至少有一個元素,累加器初始值就是數組第一個元素 accumulator = array[++index] } while (++index < length) {//循環累加 accumulator = iteratee(accumulator, array[index], index, array) } return accumulator } export default arrayReduce
baseReduce
/** * The base implementation of `reduce` and `reduceRight` which iterates * over `collection` using `eachFunc`. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} accumulator The initial value. * @param {boolean} initAccum Specify using the first or last element of * `collection` as the initial value. * @param {Function} eachFunc The function to iterate over `collection`. * @returns {*} Returns the accumulated value. */ //reduce基礎實現,使用eachFunc方法執行累加的方法 function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { eachFunc(collection, (value, index, collection) => { accumulator = initAccum ? (initAccum = false, value) : iteratee(accumulator, value, index, collection) //如果沒有提供累加初始值,就用第一個元素作為初始值 }) return accumulator } export default baseReduce
baseEach
import baseForOwn from './baseForOwn.js' import isArrayLike from '../isArrayLike.js' /** * The base implementation of `forEach`. * * @private * @param {Array|Object} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array|Object} Returns `collection`. */ //forEach的基礎實現 //collection被迭代遍歷的對象,iteratee遍歷器 function baseEach(collection, iteratee) { if (collection == null) {//如果collection為空,直接返回原對象 return collection } if (!isArrayLike(collection)) {//如果collection不是array-like對象,就調用baseForOwn處理 return baseForOwn(collection, iteratee) } const length = collection.length//對象長度 const iterable = Object(collection) let index = -1//循環索引 while (++index < length) {//循環調用iteratee方法,如果iteratee返回值是false,提前跳出循環結束 if (iteratee(iterable[index], index, iterable) === false) { break } } return collection } export default baseEach
baseForOwn
import baseFor from './baseFor.js' import keys from '../keys.js' /** * The base implementation of `forOwn`. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Object} Returns `object`. */ //forOwn方法的基礎實現 function baseForOwn(object, iteratee) { return object && baseFor(object, iteratee, keys)//如果object不為空,調用baseFor處理 } export default baseForOwn
baseFor
/** * The base implementation of `baseForOwn` which iterates over `object` * properties returned by `keysFunc` and invokes `iteratee` for each property. * Iteratee functions may exit iteration early by explicitly returning `false`. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {Function} keysFunc The function to get the keys of `object`. * @returns {Object} Returns `object`. */ //baseForOwn的基礎實現,通過keysFunc遍歷對象每一個屬性,用iteratee處理每個屬性值 //iteratee可以返回false跳出循環 function baseFor(object, iteratee, keysFunc) { const iterable = Object(object) const props = keysFunc(object)//key組成的數組 let { length } = props//key數組長度 let index = -1//循環索引 while (length--) {//遍歷key數組 const key = props[++index]//當前key if (iteratee(iterable[key], key, iterable) === false) {//調用iteratee break } } return object } export default baseFor