前端開發這個行業這幾年發展速度太快,各類新技術不斷更新,從es5到es6再到es7,從grunt,browserify到webpack,gulp,rollup,還有什麼postcss,typescript,flow...,一直都在學習新技術,做爲一個才工做不久的新人,感受心裏有點浮躁了,想鞏固一下基礎,以前聽別人說lodash的源碼很不錯,因此學習學習。我不是什麼大牛,若是有什麼分析得不對的,你們請務必要原諒我。。。。話很少說,lodash版本4.17.4,開始!。css
「Array」 Methods
_.chunk(array, [size=1])
將一個數組拆分紅多個數組的塊,而後把這些塊組成新的數組前端
//chunk.js //同Array.slice方法 var baseSlice = require('./_baseSlice'), //是不是一個遍歷方法的參數,也就是須要和Array.map的參數同樣,第一個是值,第二個是索引,第三個是對象自己 isIterateeCall = require('./_isIterateeCall'), //轉化成整型 toInteger = require('./toInteger'); var nativeCeil = Math.ceil,//原生上舍入方法 nativeMax = Math.max;//原生最大值方法 /** * @param {Array} array 須要處理的數組 * @param {Number} size 每一個數組塊的長度 * @param {Object} guard 讓chunk方法能夠做爲一個遍歷方法,好比做爲Array.map的參數(不知道有什麼用) * @returns {Array} 返回處理後的數組 * @example * * _.chunk(['a', 'b', 'c', 'd'], 2); * // => [['a', 'b'], ['c', 'd']] * * _.chunk(['a', 'b', 'c', 'd'], 3); * // => [['a', 'b', 'c'], ['d']] * */ function chunk(array, size, guard) { //判斷是否傳入guard,若是傳入,判斷是不是遍歷方法的參數,若是是size=1,不然爲傳入size和0的最大值 //若是沒傳,判斷是否傳入size,若是沒傳,size=1,不然爲傳入size和0的最大值 if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { size = 1; } else { size = nativeMax(toInteger(size), 0); } var length = array == null ? 0 : array.length;//數組長度 if (!length || size < 1) { //若是爲空,或者傳入負的size,返回空數組 return []; } var index = 0,//切數組塊的的起始位置 resIndex = 0,//返回的數組的索引 result = Array(nativeCeil(length / size));//返回的數組 //循環,每次向result添加一個size的數組塊,而且將index向後移size個位置,直到index到了原始數組的末尾 while (index < length) { result[resIndex++] = baseSlice(array, index, (index += size)); } return result;//返回切好的數組 } module.exports = chunk;
_.compact(array)
建立一個新數組幷包含原數組中全部的非假值元素。webpack
//compact.js /** * @param {Array} array 須要處理的數組 * @returns {Array} 返回處理後的數組 * @example * *_.compact([0, 1, false, 2, '', 3]); * // => [1, 2, 3] */ function compact(array) { var index = -1,//數組索引 length = array == null ? 0 : array.length,//數組長度 resIndex = 0,//結果數組索引 result = [];//結果數組 while (++index < length) {//遍歷原數組 var value = array[index]; if (value) {//若是是真值,就將它加入到結果數組中,而且讓resIndex加1 result[resIndex++] = value; } } return result;//返回結果數組 } module.exports = compact;
_.concat(array, [values])
建立一個新數組包含原來的數組和全部添加的元素和數組es6
//concat.js var arrayPush = require('./_arrayPush'),//同Array.push方法,第一個參數是原數組,第二個是須要添加的值得數組集合 baseFlatten = require('./_baseFlatten'),//數組扁平化,後面再分析,好比[1,[2,3],[4,5,[6]]] => [1,2,3,4,5,6] copyArray = require('./_copyArray'),//拷貝數組 isArray = require('./isArray');//Array.isArray方法的引用。 /** * @param {Array} array 須要處理的數組 * @param {...*} [values] 須要添加的元素或數組 * @returns {Array} 返回處理後的數組 * @example * * var array = [1]; * var other = _.concat(array, 2, [3], [[4]]); * * console.log(other); * // => [1, 2, 3, [4]] * * console.log(array); * // => [1] */ function concat() { var length = arguments.length;//參數個數 if (!length) {//沒有參數,返回空數組 return []; } var args = Array(length - 1), //包含須要添加的數組或元素的數組 array = arguments[0],//原數組 index = length;//參數索引 while (index--) {//遍歷參數,將除了第一個參數的其餘參數加入args中 args[index - 1] = arguments[index]; } //若是第一個參數是數組,先複製一份(這樣就不會修改原數組),而後將args扁平化一級([1,[2,[3]]] => [1,2,[3]])以後添加進拷貝的數組中,並返回添加以後的數組 //若是第一個參數不是數組,直接將其做爲空數組的第一個元素([array]),而後將args扁平化一級([1,[2,[3]]] => [1,2,[3]])以後添加進該數組,並返回添加以後的數組 return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); } module.exports = concat;
_.difference(array, [values])
建立一個新數組,其結果爲原數組中不包含過濾數組中的值。web
_.differenceBy(array, [values], [iteratee=_.identity])
和_.difference很像,除了他接受一個遍歷函數被每一個原數組和過濾數組中的值調用,調用以後再進行過濾。
typescript
_.differenceWith(array, [values], [comparator])
和_.difference很像,除了他接受一個比較方法被每一個原數組和過濾數組中的值調用,比較方法接受兩個參數(arrVal原數組的值,othVal過濾數組的值),比較結果爲true則過濾掉。
gulp
這三個方法都依賴於baseDifference方法,先看源碼。數組
//_baseDifference.js var SetCache = require('./_SetCache'), //Set緩存數組 arrayIncludes = require('./_arrayIncludes'),//同Array.includes方法 arrayIncludesWith = require('./_arrayIncludesWith'),//同Array.includes方法,除了他接受一個比較方法 arrayMap = require('./_arrayMap'),//同Array.map baseUnary = require('./_baseUnary'),//建立一個只有一個參數的方法,忽略其餘的參數 cacheHas = require('./_cacheHas');//判斷緩存中是否存在某個元素 var LARGE_ARRAY_SIZE = 200;//數組最大長度 /** * @param {Array} array 須要處理的數組. * @param {Array} values 須要過濾的數組. * @param {Function} [iteratee] 遍歷器,被每一個元素調用. * @param {Function} [comparator] 比較器,被每一個元素調用. * @returns {Array} 返回過濾後的數組. */ function baseDifference(array, values, iteratee, comparator) { var index = -1,//原數組索引 includes = arrayIncludes,//引用arrayIncludes isCommon = true,//是否正常過濾 length = array.length,//數組長度 result = [],//返回結構 valuesLength = values.length;//過濾數組長度 if (!length) {//若是原數組爲空或者空數組,返回空數組 return result; } if (iteratee) {//若是有遍歷器,先對過濾數組進行遍歷操做 values = arrayMap(values, baseUnary(iteratee)); } if (comparator) {//若是有比較器,includes就引用arrayIncludesWith,而且不正常過濾 includes = arrayIncludesWith; isCommon = false; } else if (values.length >= LARGE_ARRAY_SIZE) {//若是過濾數組的長度大於最大數組長度 includes = cacheHas;//includes引用cacheHas isCommon = false;//不正常過濾 values = new SetCache(values);//過濾數組等於緩存以後的數組(用於優化,暫時不分析) } //遍歷原數組 outer: while (++index < length) { var value = array[index],//每次遍歷的原數組中的元素 computed = iteratee == null ? value : iteratee(value);//若是有遍歷器,對該元素調用一次,獲得計算後的cumputed,不然computed和value同樣 value = (comparator || value !== 0) ? value : 0; if (isCommon && computed === computed) {//正常過濾而且computed不爲NaN var valuesIndex = valuesLength;//過濾數組的索引 while (valuesIndex--) { if (values[valuesIndex] === computed) {//若是這個元素在過濾數組中存在,跳過, continue outer; } } result.push(value);//若是不存在,添加添加進結果數組中 } else if (!includes(values, computed, comparator)) {//非正常過濾,調用includes方法,若是經過比較器的規則不包含,將該元素添加進結果數組 result.push(value); } } return result;//返回過濾後的數組 } module.exports = baseDifference;
相對應的方法都是在baseDiffrerece的基礎上進行擴展的緩存
//difference.js var baseDifference = require('./_baseDifference'),//baseDifference方法 baseFlatten = require('./_baseFlatten'),//數組扁平化 baseRest = require('./_baseRest'),//建立可使用rest參數的方法 isArrayLikeObject = require('./isArrayLikeObject');//是不是一個相似數組的對象 /** * * @param {Array} 須要處理的數組. * @param {...Array} [values] 須要過濾的值. * @returns {Array} 返回過濾後的數組. * @example * * _.difference([2, 1], [2, 3]); * // => [1] */ var difference = baseRest(function(array, values) {//建立一個具有rest參數的方法 //若是array是一個相似數組的對象,調用baseDifference方法,而且將全部過濾數組扁平化一級,好比difference(arr,[1,2],[3,4]) => baseDifference(arr,[1,2,3,4]) //若是不是,返回一個空數組 return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) : []; }); module.exports = difference;
//differenceBy.js var baseDifference = require('./_baseDifference'),//baseDifference方法 baseFlatten = require('./_baseFlatten'),//數組扁平化 baseIteratee = require('./_baseIteratee'),//封裝遍歷器(讓遍歷器不只能夠是函數,還能夠是屬性或者對象) baseRest = require('./_baseRest'),//建立可使用rest參數的方法 isArrayLikeObject = require('./isArrayLikeObject'),//是不是一個相似數組的對象 last = require('./last');//獲得數組的最後一個元素 /** * @param {Array} 須要處理的數組. * @param {...Array} [values] 須要過濾的值. * @param {Function} [iteratee=_.identity] 遍歷器,對每一個元素進行調用. * @returns {Array} 返回過濾後的數組.
* @example
*
*_.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
*// => [1.2]
*
* 遍歷器簡寫(寫屬性值)
*_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
*// => [{ 'x': 2 }]
*/ var differenceBy = baseRest(function(array, values) {//建立一個具有rest參數的方法 var iteratee = last(values);//遍歷器爲values的最後一個參數 if (isArrayLikeObject(iteratee)) {//若是這個參數是相似數組的對象,遍歷器爲undefined(也就是並無傳入遍歷器) iteratee = undefined; } //若是array是相似數組的對象,調用baseDifference,而且將全部過濾數組扁平化一級,再傳入建立的遍歷器 //若是不是,返回一個空數組 return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), baseIteratee(iteratee, 2)) : []; }); module.exports = differenceBy;
//differenceWith.js var baseDifference = require('./_baseDifference'),//同上 baseFlatten = require('./_baseFlatten'), baseRest = require('./_baseRest'), isArrayLikeObject = require('./isArrayLikeObject'), last = require('./last'); /** * @param {Array} array 須要處理的數組. * @param {...Array} [values] 須要過濾的值. * @param {Function} [comparator] 比較器,對每一個元素進行調用. * @returns {Array} 返回過濾後的數組. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; * * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); * // => [{ 'x': 2, 'y': 1 }] */ var differenceWith = baseRest(function(array, values) {//建立一個具有rest參數的方法 var comparator = last(values);//比較器爲values的最後一個參數 if (isArrayLikeObject(comparator)) {//若是這個參數是相似數組的對象,比較器爲undefined(也就是並無傳入比較器) comparator = undefined; } //若是array是相似數組的對象,調用baseDifference,而且將全部過濾數組扁平化一級,而且不傳遍歷器,再傳入比較器 return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) : []; }); module.exports = differenceWith;
_.drop(array, [n=1])
將 array 中的前 n 個元素去掉,而後返回剩餘的部分ide
//drop.js var baseSlice = require('./_baseSlice'),//同Array.slice toInteger = require('./toInteger');//轉化爲整型 /** * * @param {Array} array 須要處理的數組. * @param {number} [n=1] 須要去掉的個數. * @param- {Object} [guard] 使這個方法可以做爲遍歷器被調用,好比_.map(drop). * @returns {Array} 返回處理後的數組. * @example * * _.drop([1, 2, 3]); * // => [2, 3] * * _.drop([1, 2, 3], 2); * // => [3] * * _.drop([1, 2, 3], 5); * // => [] * * _.drop([1, 2, 3], 0); * // => [1, 2, 3] */ function drop(array, n, guard) { var length = array == null ? 0 : array.length;//數組長度 if (!length) {//若是爲空數組,返回空數組 return []; } n = (guard || n === undefined) ? 1 : toInteger(n);//將n轉爲整型 return baseSlice(array, n < 0 ? 0 : n, length);//調用baseSlice對數組從n位置進行切割,並返回切好的數組 } module.exports = drop;
_.dropRight(array, [n=1])
將 array 尾部的 n 個元素去除,並返回剩餘的部分。
//dropRight.js var baseSlice = require('./_baseSlice'),//同Array.slice toInteger = require('./toInteger');//轉化爲整型 /** * * @param {Array} array 須要處理的數組. * @param {number} [n=1] 須要去掉的個數. * @param- {Object} [guard] 使這個方法可以做爲遍歷器被調用,好比_.map(dropRight). * @returns {Array} 返回處理後的數組. * @example * * _.dropRight([1, 2, 3]); * // => [1, 2] * * _.dropRight([1, 2, 3], 2); * // => [1] * * _.dropRight([1, 2, 3], 5); * // => [] * * _.dropRight([1, 2, 3], 0); * // => [1, 2, 3] */ function dropRight(array, n, guard) { var length = array == null ? 0 : array.length;//數組長度 if (!length) {//若是爲空數組,返回空數組 return []; } n = (guard || n === undefined) ? 1 : toInteger(n);//將n轉爲整型 n = length - n;//剩下的個數 return baseSlice(array, 0, n < 0 ? 0 : n);//調用baseSlice對數組從0位置進行切割n個,並返回切好的數組 } module.exports = dropRight;
_.dropRightWhile(array, [predicate=_.identity])
從末尾對數組進行截取,從第一個不知足predicate 條件的元素開始截取數組。predicate接受三個參數(value,index,array)
_.dropWhile(array, [predicate=_.identity])
從開始對數組進行截取,從第一個不知足predicate 條件的元素開始截取數組。predicate接受三個參數(value,index,array)
這兩個方法依賴於baseWhile方法,先看源碼
//_baseWhile.js var baseSlice = require('./_baseSlice');//同Array.slice /** *_.dropWhile和_.takeWhile的基本實現,可是不支持遍歷器的簡寫(不能直接寫一個屬性或對象進行遍歷) * * @param {Array} array 須要處理的數組. * @param {Function} predicate 迭代判斷條件. * @param {boolean} [isDrop] 指定是移除仍是獲取這些元素. * @param {boolean} [fromRight] 指定從開始仍是末尾開始判斷. * @returns {Array} 返回處理後的數組. */ function baseWhile(array, predicate, isDrop, fromRight) { var length = array.length,//數組長度 index = fromRight ? length : -1;//數組索引,若是是從末尾判斷,則爲length,不然爲0 //遍歷每一個元素,而且調用判斷方法,直到判斷結果爲false,而後獲得此時的index while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} //若是是刪除元素,若是從末尾開始,調用baseSlice(0,index+1),不然調用baseSlice(index,length) //若是是獲取元素,若是從末尾開始,調用baseSlice(index+1,length),不然調用baseSlice(0,index) //最後返回切好的數組 return isDrop ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); } module.exports = baseWhile;
相對應的方法都是在baseWhile的基礎上進行擴展的
//dropRightWhile.js var baseIteratee = require('./_baseIteratee'),//封裝遍歷器 baseWhile = require('./_baseWhile');//baseWhile方法 /** * * @param {Array} array 須要處理的數組. * @param {Function} [predicate=_.identity] 迭代判斷條件. * @returns {Array} 返回切好的數組. * @example * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * * _.dropRightWhile(users, function(o) { return !o.active; }); * // => objects for ['barney'] */ function dropRightWhile(array, predicate) { //若是array存在,而且不爲空數組,調用baseWhile方法,傳入該數組,遍歷器,而後指定從右邊開始移除 //不然返回空數組 return (array && array.length) ? baseWhile(array, baseIteratee(predicate, 3), true, true) : []; } module.exports = dropRightWhile;
//dropWhile.js var baseIteratee = require('./_baseIteratee'),//封裝遍歷器 baseWhile = require('./_baseWhile');//baseWhile方法 /** * * @param {Array} array 須要處理的數組. * @param {Function} [predicate=_.identity] 迭代判斷條件. * @returns {Array} 返回切好的數組. * @example * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * * _.dropWhile(users, function(o) { return !o.active; }); * // => objects for ['pebbles'] */ function dropWhile(array, predicate) { //若是array存在,而且不爲空數組,調用baseWhile方法,傳入該數組,遍歷器,而後指定從左邊開始移除 //不然返回空數組 return (array && array.length) ? baseWhile(array, baseIteratee(predicate, 3), true) : []; } module.exports = dropWhile;
_.fill(array, value, [start=0], [end=array.length])
使用 value 值來填充(也就是替換) array,從start位置開始, 到end位置結束(但不包含end位置)
此方法依賴於baseFill方法,先看源碼
//_baseFill.js var toInteger = require('./toInteger'),//轉換爲整型 toLength = require('./toLength');//轉換爲可使用的length /** * 使用 value 值來填充(也就是替換) array,從start位置開始, 到end位置結束(但不包含end位置) * * @private * @param {Array} array 須要處理的數組. * @param {*} value 填充的值. * @param {number} [start=0] 填充的開始位置 * @param {number} [end=array.length] 填充的結束位置. * @returns {Array} 返回處理後的數組. */ function baseFill(array, value, start, end) { var length = array.length;//數組長度 start = toInteger(start);//轉換爲整型 if (start < 0) {//若是start爲負值,從末尾開始算,-1就是最後一個元素,依次計算,若是最後大於數組的長度,就是0 start = -start > length ? 0 : (length + start); } //對end進行判斷,取得合適的end end = (end === undefined || end > length) ? length : toInteger(end); if (end < 0) {//若是start爲負值,從末尾開始算,-1就是最後一個元素,依次計算,若是最後大於數組的長度,就是0 end += length; } //若是start大於end,end等於0,不然將end轉爲可用的length end = start > end ? 0 : toLength(end); //循環,每次start+1直到start=end while (start < end) { array[start++] = value;//將對應索引的元素替換爲value } return array;//返回該數組 } module.exports = baseFill;
再看fill.js
//fill.js var baseFill = require('./_baseFill'),//baseFill方法 isIterateeCall = require('./_isIterateeCall');//判斷是否爲遍歷器的參數(value,index,array) /** * * @param {Array} array 須要處理的數組. * @param {*} value 填充的值. * @param {number} [start=0] 填充的開始位置 * @param {number} [end=array.length] 填充的結束位置. * @returns {Array} 返回處理後的數組. * @example * * var array = [1, 2, 3]; * * _.fill(array, 'a'); * console.log(array); * // => ['a', 'a', 'a'] * * _.fill(Array(3), 2); * // => [2, 2, 2] * * _.fill([4, 6, 8, 10], '*', 1, 3); * // => [4, '*', '*', 10] */ function fill(array, value, start, end) { var length = array == null ? 0 : array.length;//數組長度 if (!length) {//若是爲空數組,返回空數組 return []; } //若是start存在且不爲number且爲遍歷器,那麼start=0,end=length(也就是說將fill做爲參數傳入map之類的方法,暫時不知道有什麼用) if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { start = 0; end = length; } return baseFill(array, value, start, end); //調用baseFill而且將結果數組返回 } module.exports = fill;
_.findIndex(array, [predicate=_.identity], [fromIndex=0])
對數組從開始進行查找,該方法返回符合判斷條件的第一個元素的索引
_.findLastIndex(array, [predicate=_.identity], [fromIndex=array.length-1])
對數組從末尾進行查找,該方法返回符合判斷條件的第一個元素的索引
這兩個方法依賴於baseFindIndex方法,先看源碼
//_baseFindIndex.js /** *_.findIndex和_.findLastIndex的基本實現,可是不支持遍歷方法的簡寫(不能直接寫一個屬性或對象進行遍歷) * * @private * @param {Array} array 須要處理的數組. * @param {Function} predicate 判斷方法,對每一個元素調用. * @param {number} fromIndex 開始查找的位置. * @param {boolean} [fromRight] 指定從開始仍是末尾開始搜索. * @returns {number} 返回匹配的值的索引,不然返回-1. */ function baseFindIndex(array, predicate, fromIndex, fromRight) { var length = array.length,//數組長度 index = fromIndex + (fromRight ? 1 : -1);//數組索引 //循環,對每一個元素調用判斷方法,若是結果爲true,返回對應的index while ((fromRight ? index-- : ++index < length)) { if (predicate(array[index], index, array)) { return index; } } return -1;//返回-1 } module.exports = baseFindIndex;
相對應的方法都是在baseFindIndex的基礎上進行擴展的
//findIndex.js var baseFindIndex = require('./_baseFindIndex'),//baseFindIndex方法 baseIteratee = require('./_baseIteratee'),//封裝遍歷器(讓遍歷器不只能夠是函數,還能夠是屬性或者對象) toInteger = require('./toInteger');//轉換爲整型 var nativeMax = Math.max;//原生最大值方法 /** * * @param {Array} array 須要處理的數組. * @param {Function} [predicate=_.identity] 遍歷器,對每一個元素調用. * @param {number} [fromIndex=0] 開始查找的位置. * @returns {number} 返回匹配的值的索引,不然返回-1. * @example * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * * _.findIndex(users, function(o) { return o.user == 'barney'; }); * // => 0 */ function findIndex(array, predicate, fromIndex) { var length = array == null ? 0 : array.length;//數組長度 if (!length) {//若是爲空數組,返回-1 return -1; } var index = fromIndex == null ? 0 : toInteger(fromIndex);//開始查找的索引 if (index < 0) {//若是index爲負值,從末尾開始算,-1就是最後一個元素,依次計算,若是最後大於數組的長度,就是0 index = nativeMax(length + index, 0); } //調用baseFindIndex,而且將遍歷方法封裝,而後將結果做爲返回值返回 return baseFindIndex(array, baseIteratee(predicate, 3), index); } module.exports = findIndex;
//findLastIndex.js var baseFindIndex = require('./_baseFindIndex'),//baseFindIndex方法 baseIteratee = require('./_baseIteratee'),//封裝遍歷器(讓遍歷器不只能夠是函數,還能夠是屬性或者對象) toInteger = require('./toInteger');//轉換爲整型 var nativeMax = Math.max, nativeMin = Math.min; /** * * @param {Array} array 須要處理的數組. * @param {Function} [predicate=_.identity] 遍歷器,對每一個元素調用. * @param {number} [fromIndex=0] 開始查找的位置. * @returns {number} 返回匹配的值的索引,不然返回-1. * @example * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); * // => 2 */ function findLastIndex(array, predicate, fromIndex) { var length = array == null ? 0 : array.length;//數組長度 if (!length) {//若是爲空數組,返回-1 return -1; } var index = length - 1;//開始查找的索引 if (fromIndex !== undefined) {//若是有fromIndex,進行比較,獲得正確的index(負值反向且不能超過數組長度) index = toInteger(fromIndex); index = fromIndex < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); } //調用baseFindIndex方法,而且封裝遍歷器,而且指定從右邊查找,最後將結果做爲返回值返回 return baseFindIndex(array, baseIteratee(predicate, 3), index, true); } module.exports = findLastIndex;
_.find(collection, [predicate=_.identity], [fromIndex=0])
從開始對集合進行查找,該方法返回符合判斷條件的第一個元素
_.findLast(collection, [predicate=_.identity], [fromIndex=0])
從末尾對集合進行查找,該方法返回符合判斷條件的第一個元素
這兩個方法是屬於集合的方法,依賴於createFind方法和上面的findIndex和findLastIndex方法,因此就在這裏一塊兒分析了,先看createFind的源碼
//_createFind.js var baseIteratee = require('./_baseIteratee'), isArrayLike = require('./isArrayLike'), keys = require('./keys'); /** * 建立一個_.find或者_.findLast方法 * * @private * @param {Function} findIndexFunc 查找集合index的方法. * @returns {Function} 返回新的查找方法. */ function createFind(findIndexFunc) { return function(collection, predicate, fromIndex) { var iterable = Object(collection);//將集合轉爲對象 if (!isArrayLike(collection)) {//若是不是相似數組的對象(就是常規的對象) var iteratee = baseIteratee(predicate, 3); collection = keys(collection);//集合爲這個對象的key的集合 predicate = function(key) { return iteratee(iterable[key], key, iterable); };//重寫判斷方法 } var index = findIndexFunc(collection, predicate, fromIndex);//調用findIndexFunc方法,取得索引 //若是index>-1 就取得這個索引對應的值,不然爲undefined,而且將結果返回 return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; }; } module.exports = createFind;
find方法至關因而調用createFind傳入findIndex,lastFind方法至關因而調用createFind傳入findLastIndex
//find.js var createFind = require('./_createFind'),//createFind方法 findIndex = require('./findIndex');//findIndex方法 /** * * @param {Array} array 須要處理的數組. * @param {Function} [predicate=_.identity] 遍歷器,對每一個元素調用. * @param {number} [fromIndex=0] 開始查找的位置. * @returns {number} 返回匹配的值,或者undefined. * @example * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false }, * { 'user': 'pebbles', 'age': 1, 'active': true } * ]; * * _.find(users, function(o) { return o.age < 40; }); * // => object for 'barney' */ var find = createFind(findIndex);//建立find方法 module.exports = find;
//findLast.js var createFind = require('./_createFind'),//createFind方法 findLastIndex = require('./findLastIndex');//findIndex方法 /** * * @param {Array} array 須要處理的數組. * @param {Function} [predicate=_.identity] 遍歷器,對每一個元素調用. * @param {number} [fromIndex=0] 開始查找的位置. * @returns {number} 返回匹配的值,或者undefined. * @example * * _.findLast([1, 2, 3, 4], function(n) { * return n % 2 == 1; * }); * // => 3 */ var findLast = createFind(findLastIndex);//建立find方法 module.exports = findLast;
_.head(array)/
_.first(array)
獲得數組的第一個元素
//head.js /** * * @param {Array} array 須要處理的數組. * @returns {*} Returns 數組的第一個元素. * @example * * _.head([1, 2, 3]); * // => 1 * * _.head([]); * // => undefined */ function head(array) { return (array && array.length) ? array[0] : undefined;//不解釋 } module.exports = head;
//first.js module.exports = require('./head');
_.flatten(array)
對數組執行扁平化一級操做
_.flattenDeep(array)
對數組遞歸的執行扁平化操做.
_.flattenDepth(array, [depth=1])
對數組執行扁平化depth級操做.
數組扁平化的幾種方法依賴於baseFlatten方法,先看源碼
//_baseFlatten.js var arrayPush = require('./_arrayPush'),//同Array.push isFlattenable = require('./_isFlattenable');//是否能夠扁平化 /** * _.flatten的基本實現,支持是否限制扁平化操做 * * @param {Array} array 須要處理的數組. * @param {number} depth 扁平化的深度. * @param {boolean} [predicate=isFlattenable] 判斷是否執行扁平化操做,對每一個元素進行調用. * @param {boolean} [isStrict] 是否遵照predicate的檢查. * @param {Array} [result=[]] 初始化結果值. * @returns {Array} 返回扁平化以後的數組. */ function baseFlatten(array, depth, predicate, isStrict, result) { var index = -1,//數組索引 length = array.length;//數組長度 predicate || (predicate = isFlattenable);//若是沒有傳入判斷方法,這判斷方法爲isFlattenable(只有能夠執行扁平化就執行) result || (result = []);//若是沒有傳入的初始的結果數組,則結果爲空數組 //遍歷數組中的每一個元素 while (++index < length) { var value = array[index];//元素值 if (depth > 0 && predicate(value)) {//若是深度大於0而且經過了檢查 if (depth > 1) {//若是深度大於1(還須要扁平化),遞歸調用自身,而且depth-1,不然將這個元素值添加到結果數組 baseFlatten(value, depth - 1, predicate, isStrict, result); } else { arrayPush(result, value); } } else if (!isStrict) {//若是不須要遵照判斷規則,直接將value添加到結果中 result[result.length] = value; } } return result;//返回結果數組 } module.exports = baseFlatten;
相對應的方法都是在baseFlatten的基礎上擴展的
//flatten.js var baseFlatten = require('./_baseFlatten');//baseFlatten方法 /** * * @param {Array} array 須要處理的數組. * @returns {Array} Returns 扁平化以後數組. * @example * * _.flatten([1, [2, [3, [4]], 5]]); * // => [1, 2, [3, [4]], 5] */ function flatten(array) { var length = array == null ? 0 : array.length;//數組長度 return length ? baseFlatten(array, 1) : [];//若是不是空數組,調用baseFlatten(只扁平化一級),並將結果返回,不然,返回空數組 } module.exports = flatten;
//flattenDeep.js var baseFlatten = require('./_baseFlatten');//baseFlatten方法 var INFINITY = 1 / 0;//無限大 /** * * @param {Array} array 須要處理的數組. * @returns {Array} 返回扁平化以後的數組. * @example * * _.flattenDeep([1, [2, [3, [4]], 5]]); * // => [1, 2, 3, 4, 5] */ function flattenDeep(array) { var length = array == null ? 0 : array.length;//數組長度 return length ? baseFlatten(array, INFINITY) : [];//若是不是空數組,調用baseFlatten(遞歸調用,直到不能扁平化爲止),並將結果返回,不然,返回空數組 } module.exports = flattenDeep;
//flattenDepth.js var baseFlatten = require('./_baseFlatten'),//baseFlatten方法 toInteger = require('./toInteger');//轉化爲整型 /** * @param {Array} array 須要處理的數組. * @param {number} [depth=1] 扁平化的深度. * @returns {Array} 返回扁平化以後的數組. * @example * * var array = [1, [2, [3, [4]], 5]]; * * _.flattenDepth(array, 1); * // => [1, 2, [3, [4]], 5] * * _.flattenDepth(array, 2); * // => [1, 2, 3, [4], 5] */ function flattenDepth(array, depth) { var length = array == null ? 0 : array.length;//數組長度 if (!length) {//若是爲空數組,返回空數組 return []; } depth = depth === undefined ? 1 : toInteger(depth);//扁平化的深度 return baseFlatten(array, depth);//遞歸調用depth次baseFlatten,而後將結果做爲返回值返回。 } module.exports = flattenDepth;
_.fromPairs(pairs)
將鍵值對的數組轉化爲鍵值對的對象
//fromPairs.js /** * * @param {Array} pairs 鍵值對的數組. * @returns {Object} 返回新的對象. * @example * * _.fromPairs([['a', 1], ['b', 2]]); * // => { 'a': 1, 'b': 2 } */ function fromPairs(pairs) { var index = -1,//數組索引 length = pairs == null ? 0 : pairs.length,//數組長度 result = {};//結果對象 //遍歷數組中的值 while (++index < length) { var pair = pairs[index];//鍵值對的值 result[pair[0]] = pair[1];//將第一個做爲鍵,第二個做爲值添加到結果對象中 } return result;//返回結果對象 } module.exports = fromPairs;
先到這裏了,下次繼續,慢慢來,一步一個腳印~~~