摘要:對多個一維數組進行并運算,實際上就是加強版的。所以我要說的是這個函數,將傳入參數轉換為一個數組進行到的回調函數中,以此達到函數接到的是一個一維數組的集合。
每次小章節的開題都煩惱寫什么好,所以直接接下文 (~o▔▽▔)~o o~(▔▽▔o~) 。
_.first = _.head = _.take = function(array, n, guard) { if (array == null) return void 0; if (n == null || guard) return array[0]; return _.initial(array, array.length - n); };
_.first 用于返回數組中從左到右指定數目 n 的結果集,傳入 array、n、guard 三個參數中 array 只能為 Array,當 n = null 時返回數組第一個元素,這里需要講解的是 _.initial 函數是與 _.first 完全對立的函數,它用于返回數組中從左到右指定數目 Array.length - n 的結果集。
_.initial = function(array, n, guard) { return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); };
那么它是如何實現的呢,依然是應用數組 Array 的 Array.prototype.slice.call(array, start, end); 實現,這個概念請參看:Array.prototype.slice()。
_.last = function(array, n, guard) { if (array == null) return void 0; if (n == null || guard) return array[array.length - 1]; return _.rest(array, Math.max(0, array.length - n)); };
_.last 是返回數組中從右到左指定數目 n 的結果集。實現原理依舊 Array.prototype.slice.call(array, start, end);
_.rest = _.tail = _.drop = function(array, n, guard) { return slice.call(array, n == null || guard ? 1 : n); };
_.rest 用于返回數組中從右到左指定數目 Array.length - n 的結果集。
_.compact = function(array) { return _.filter(array, Boolean); };
_.compact,我喜歡稱它為過濾器,過濾壞的數據,那么什么樣的數據為壞數據呢,我們可以看下 _.filter,前面講 _.filter 接收三個參數 obj, predicate, context,其中 predicate 依舊由 cb 處理,那么這里 _.compact 傳的 predicate 是 Boolean = function Boolean() { [native code] },這是一個 JAVASCRIPT 內置的函數用于 Boolean 判斷,我們可以參考 Boolean 和 Boolean data type。那么重點來了,什么的值會是 Boolean 函數斷言為 false 呢,答案就是 false, 0, "", null, undefined, NaN,這個可不是我瞎說或者 copy 官網,我是有理論依據的(v?v),當當當,看這里 Truthy。
var flatten = function(input, shallow, strict, output) { output = output || []; var idx = output.length; for (var i = 0, length = getLength(input); i < length; i++) { var value = input[i]; if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { if (shallow) { var j = 0, len = value.length; while (j < len) output[idx++] = value[j++]; } else { flatten(value, shallow, strict, output); idx = output.length; } } else if (!strict) { output[idx++] = value; } } return output; };
flatten 傳入四個參數,input, shallow, strict, output,其中我們可以通過 flatten 內部的 for 循環中 length = getLength(input); 知道 input 數據類型為 Array。然后通過對 shallow, strict 兩個 Boolean 型變量的控制執行相應的數據處理方式。比如 shallow 為 false 會一直執行 flatten(value, shallow, strict, output); 和 output[idx++] = value; 對多維數組進行一維數組的轉換。
_.flatten = function(array, shallow) { return flatten(array, shallow, false); };
_.flatten 函數用于對多維度數組進行扁平化處理,即將任意維數的數組轉換為一維數組,上面已經說到了這個的實現方式。
_.without = restArgs(function(array, otherArrays) { return _.difference(array, otherArrays); });
_.without 用于刪除數組中的某些特定元素。它由 _.difference 構成。
_.uniq = _.unique = function(array, isSorted, iteratee, context) { if (!_.isBoolean(isSorted)) { context = iteratee; iteratee = isSorted; isSorted = false; } if (iteratee != null) iteratee = cb(iteratee, context); var result = []; var seen = []; for (var i = 0, length = getLength(array); i < length; i++) { var value = array[i], computed = iteratee ? iteratee(value, i, array) : value; if (isSorted) { if (!i || seen !== computed) result.push(value); seen = computed; } else if (iteratee) { if (!_.contains(seen, computed)) { seen.push(computed); result.push(value); } } else if (!_.contains(result, value)) { result.push(value); } } return result; };
_.uniq 是數組去重,實現原理是如果 isSorted 及后面元素省略,那么 _.uniq 簡化為:
_.uniq = _.unique = function(array) { context = null; iteratee = null; isSorted = false; var result = []; var seen = []; for (var i = 0, length = getLength(array); i < length; i++) { var value = array[i]; if (!_.contains(result, value)) { result.push(value); } } return result; };
我們可以看到其核心代碼只有 if (!_.contains(result, value)),用于判斷數組中是否包含其值,以此達到數組去重的目的。是這里我想說的是 context、iteratee、isSorted 變成了未定義的參數,作者沒有處理它會在這種情況下變成全局污染。
接下來我們說一下傳入 array, isSorted, iteratee 三個參數的情況,我們已經知道 isSorted 默認為 false,代表去重,那么如果定義 isSorted 為 true 則就是不去重,如果 isSorted 是回調函數,則默認內部重新定義 isSorted 為 false,并將回調函數賦給 iteratee,然后很悲劇的 iteratee 參數依然是沒有 var 過的,又污染了啊(?_??) 。大致就是這醬了。
_.union = restArgs(function(arrays) { return _.uniq(flatten(arrays, true, true)); });
_.union 對多個一維數組進行并運算,實際上就是加強版的 _.uniq。在代碼中作者首先用 flatten 函數處理參數,之前我們說到 flatten 是用于多個多維數組進行一位轉換,實際上就是要把 arrays 轉換。這里有同學可能問道 flatten 直接收一個 Array 剩下的值是 Boolean 啊,那么使用 _.union 的時候是一次性傳入 n 個 Array(如這樣:_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);),說不通啊。所以我要說的是 restArgs 這個函數,將傳入參數轉換為一個數組進行 func.apply(this, args) 到 restArgs 的回調函數 function(arrays) {} 中,以此達到 flatten 函數 arrays 接到的是一個一維數組的集合。最后通過 _.uniq 函數對數組進行處理。
_.intersection = function(array) { var result = []; var argsLength = arguments.length; for (var i = 0, length = getLength(array); i < length; i++) { var item = array[i]; if (_.contains(result, item)) continue; var j; for (j = 1; j < argsLength; j++) { if (!_.contains(arguments[j], item)) break; } if (j === argsLength) result.push(item); } return result; };
_.intersection 用于獲取多個一維數組的相同數據的集合,即交集。又是一番對 Array 的 for 啊 for 啊 for,然后 if 然后 push,相信大家這么聰明,不用多說了,因為這個函數很直白,沒太多可講的。
_.difference = restArgs(function(array, rest) { rest = flatten(rest, true, true); return _.filter(array, function(value){ return !_.contains(rest, value); }); });
_.difference 函數的實現與 _.union 類似,都是通過 restArgs 對 n 個傳參進行數組轉變,然后賦給回調函數,區別在于這個函數可能更加復雜,它首先 restArgs 回調寫了兩個傳參 array, rest,但實際上 rest 是 undefined,之后在回調內部給 rest 賦值為 flatten 函數處理之后的數組,即扁平化后的一維數組。因為 restArgs 函數只有一個 function 回調,所以內部執行 return func.call(this, arguments[0], rest);,返回的是第一個數組和其他數組的集合,即 array, rest。
_.unzip = function(array) { var length = array && _.max(array, getLength).length || 0; var result = Array(length); for (var index = 0; index < length; index++) { result[index] = _.pluck(array, index); } return result; };
_.unzip 用于將多個數組中元素按照數組下標進行拼接,只接收一個二維數組,返回值同樣是一個二維數組。
_.zip = restArgs(_.unzip);
_.zip 與 _.unzip 不同之處在于它可以傳入不定的一維數組參數然后通過 restArgs 函數轉換實現 _.unzip 傳參的效果。
_.object = function(list, values) { var result = {}; for (var i = 0, length = getLength(list); i < length; i++) { if (values) { result[list[i]] = values[i]; } else { result[list[i][0]] = list[i][1]; } } return result; };
_.object 用于將數組轉換成對象。
var createPredicateIndexFinder = function(dir) { return function(array, predicate, context) { predicate = cb(predicate, context); var length = getLength(array); var index = dir > 0 ? 0 : length - 1; for (; index >= 0 && index < length; index += dir) { if (predicate(array[index], index, array)) return index; } return -1; }; };
createPredicateIndexFinder 這個函數適用于生成 _.findIndex 之類的函數,當我們看到 return index; 的是后就已經可以知道,其核心是與數組下標有關。
_.findIndex = createPredicateIndexFinder(1);
_.findIndex 函數由 createPredicateIndexFinder 包裝而成,我們可以看到它的默認傳值是 1,也就是:
_.findIndex = function(array, predicate, context) { predicate = cb(predicate, context); for (var index >= 0; index < getLength(array); index += 1) { if (predicate(array[index], index, array)) return index; } return -1; };
其中 predicate 是回調函數接收 array[index], index, array 三個值用于 Boolean 判斷,最終結果是返回符合規則的數組中的第一條數據的數組下標。
_.findLastIndex = createPredicateIndexFinder(-1);
_.findLastIndex 顧名思義就是返回數組中符合規則的最后一條數據的下標,說直白了就是遍歷數組的時候從右往左而已。
_.sortedIndex = function(array, obj, iteratee, context) { iteratee = cb(iteratee, context, 1); var value = iteratee(obj); var low = 0, high = getLength(array); while (low < high) { var mid = Math.floor((low + high) / 2); if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; } return low; };
_.sortedIndex 官網解釋說 使用二分查找確定value在list中的位置序號,value按此序號插入能保持list原有的排序。,很繞口,這里我們需要注意的是如果進行 _.sortedIndex 查找這個特定的序列號,一定要事先將 array 進行按需排序。
var createIndexFinder = function(dir, predicateFind, sortedIndex) { return function(array, item, idx) { var i = 0, length = getLength(array); if (typeof idx == "number") { if (dir > 0) { i = idx >= 0 ? idx : Math.max(idx + length, i); } else { length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; } } else if (sortedIndex && idx && length) { idx = sortedIndex(array, item); return array[idx] === item ? idx : -1; } if (item !== item) { idx = predicateFind(slice.call(array, i, length), _.isNaN); return idx >= 0 ? idx + i : -1; } for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { if (array[idx] === item) return idx; } return -1; }; };
createIndexFinder,看命名就可以知道依舊與數組下標有關。我們可以看到數據處理的一個關鍵是 idx,它可能是一個數字也可能是一個字符串或者對象。當它是 Number 的時候遵循 idx 是限制查找范圍的數組下標規則,如果它是其他的則使用 sortedIndex 函數查找到 idx 的數組下標再歲數組查找范圍進行限定。
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
_.indexOf 函數與 _.findIndex 區別在于 _.findIndex 需要查找的數據可能存在于數組中也可能不存在數組中,而 _.indexOf 的 predicateFind 一定是數組中的元素。同時也用 array, item, idx 三個參數中的 idx 限定開始查找的范圍。
_.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
_.lastIndexOf 查找數組中的符合結果的最后條數據的數組下標。
_.range = function(start, stop, step) { if (stop == null) { stop = start || 0; start = 0; } if (!step) { step = stop < start ? -1 : 1; } var length = Math.max(Math.ceil((stop - start) / step), 0); var range = Array(length); for (var idx = 0; idx < length; idx++, start += step) { range[idx] = start; } return range; };
_.range 用于生成一個有序的數組,通過 start 和 stop 限定數組范圍,通過 step 限定差值。
_.chunk = function(array, count) { if (count == null || count < 1) return []; var result = []; var i = 0, length = array.length; while (i < length) { result.push(slice.call(array, i, i += count)); } return result; };
_.chunk,這個函數目前官網并沒有釋義,估計作者忘記加進去了吧,我們看到 chunk 很自然的就應該想到 stream 的概念,這里也差不多,只不過拆分的不限定是 Buffer 數組, _.chunk 傳入兩個參數 Array 以及 count,其中 count 用來限定拆分出的每一組的大小,舉個栗子:
_.chunk([1,2,3,4,5,6,7,8,9], 1) [[1],[2],[3],[4],[5],[6],[7],[8],[9]] _.chunk([1,2,3,4,5,6,7,8,9], 2) [[1,2],[3,4],[5,6],[7,8],[9]]
然而但凡對 stream 的概念有所了解都知道這個函數吧,沒什么特殊的地方。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86341.html
摘要:組件的選擇命令行工具首先我們需要一個命令行工具來方便的執行命令,這里我們選擇組件,如果不喜歡使用且有能力的人完全可以通過組件自己封裝執行命令函數。 對于一個成熟的項目而言,一定需要一個注釋文檔生成工具,我們有很多可選的開源項目,如jsdoc、yuidocjs 等等,擁有這些強大的工具我們完全可以勝任任何注釋方面的管理了么? 一個成熟的開發者都會知道不管怎么樣的項目都會在不同的開發條件下...
摘要:新出臺的則規定,包括六種原始類型和,還有一種,詳見數據類型和數據結構。用于返回一個由給定對象的所有可枚舉自身屬性的屬性名組成的數組,。接下來判斷數字進行相應的操作,其中有和兩個方法,詳見和。 一直想寫一篇這樣的文章,于是心動不如行動,這里選擇的是 Underscore.js 1.8.3 版本,源碼注釋加在一起1625行。 Underscore.js 1.8.3 http://unde...
摘要:第四個判斷如果是對象執行返回一個斷言函數,用來判定傳入對象是否匹配指定鍵值屬性。都不匹配最后執行,返回傳入的對象的屬性。設置的值并生成函數,等同于,使具有屬性且有值則返回,否則返回,這是一個判斷函數。 在第二小章節里面我按照源碼順序介紹幾個方法,源碼緊接著第一章繼續: var builtinIteratee; builtinIteratee,內置的 Iteratee (迭代器)。...
摘要:接收三個參數分別為回調和,其中與是可選參數。官網釋義排序一個列表組成一個組,并且返回各組中的對象的數量的計數。類似,但是不是返回列表的值,而是返回在該組中值的數目。 繼續前面的內容,前文我們提到了很多方法的講解,其實到這里就已經差不多了,因為大部分代碼其實都是套路,一些基礎函數再靈活變化就可以組成很多實用的功能。 _.sortBy = function(obj, iteratee,...
摘要:傳入值進行判斷以此決定函數,將三個參數包括回調傳入中其中回調函數充當迭代器進行真值檢測,最后。是從一個中隨機返回值,并且返回值受限于這個參數,如果沒有傳入或者傳入了則執行語句,目的是將判斷處理之后返回單一值。 今天繼續上次的內容,之前我們講到了 reduce 的用法,其實我覺得用法倒是其次的關鍵是作者實現 reduce 過程中所靈活用到的函數處理方法,我們只要有心稍加總覺完全可以拿來主...
閱讀 1688·2021-11-15 11:38
閱讀 4548·2021-09-22 15:33
閱讀 2348·2021-08-30 09:46
閱讀 2195·2019-08-30 15:43
閱讀 841·2019-08-30 14:16
閱讀 2087·2019-08-30 13:09
閱讀 1267·2019-08-30 11:25
閱讀 715·2019-08-29 16:42