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