摘要:今天要講的是數(shù)組展開以及和數(shù)組展開息息相關(guān)的一個重要的內(nèi)部方法。也是個布爾值,當(dāng)為并且也為時,能過濾參數(shù)元素中的非數(shù)組元素。首先并不需要對數(shù)組深度展開,其次傳入的是數(shù)組,對于非數(shù)組元素可以直接忽略。
Why underscore
(覺得這一段眼熟的童鞋可以直接跳到正文了...)
最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中。
閱讀一些著名框架類庫的源碼,就好像和一個個大師對話,你會學(xué)到很多。為什么是 underscore?最主要的原因是 underscore 簡短精悍(約 1.5k 行),封裝了 100 多個有用的方法,耦合度低,非常適合逐個方法閱讀,適合樓主這樣的 JavaScript 初學(xué)者。從中,你不僅可以學(xué)到用 void 0 代替 undefined 避免 undefined 被重寫等一些小技巧 ,也可以學(xué)到變量類型判斷、函數(shù)節(jié)流&函數(shù)去抖等常用的方法,還可以學(xué)到很多瀏覽器兼容的 hack,更可以學(xué)到作者的整體設(shè)計(jì)思路以及 API 設(shè)計(jì)的原理(向后兼容)。
之后樓主會寫一系列的文章跟大家分享在源碼閱讀中學(xué)習(xí)到的知識。
underscore-1.8.3 源碼解讀項(xiàng)目地址 https://github.com/hanzichi/underscore-analysis
underscore-1.8.3 源碼全文注釋 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/underscore-1.8.3-analysis.js
underscore-1.8.3 源碼解讀系列文章 https://github.com/hanzichi/underscore-analysis/issues
歡迎圍觀~ (如果有興趣,歡迎 star & watch~)您的關(guān)注是樓主繼續(xù)寫作的動力
flatten端午休息三天,睡了兩天,是該有點(diǎn)產(chǎn)出了。
今天要講的是數(shù)組展開以及和數(shù)組展開息息相關(guān)的一個重要的內(nèi)部方法 flatten。
什么是數(shù)組展開?簡單的說就是將嵌套的數(shù)組 "鋪平",還是舉幾個簡單的例子吧。
[[[1, 2], [1, 2, 3]], [1, 2]] => [1, 2, 1, 2, 3, 1, 2] [[[1, 2], [1, 2, 3]], [1, 2]] => [[1, 2], [1, 2, 3], 1, 2]
以上兩種都是數(shù)組展開,第一種我們認(rèn)為是深度展開,即打破所有嵌套數(shù)組,將元素提取出來放入一個數(shù)組中;第二種只展開了一層,即只把數(shù)組內(nèi)嵌套的一層數(shù)組展開,而沒有遞歸展開下去。
我們首先來看看 flatten 方法的調(diào)用形式。
var flatten = function(input, shallow, strict, startIndex) { // ... };
第一個參數(shù) input 即為需要展開的數(shù)組,所以 flatten 方法中傳入的第一個參數(shù)肯定是數(shù)組(或者 arguments);第二個參數(shù) shallow 是個布爾值,如果為 false,則表示數(shù)組是深度展開,如果為 true 則表示只展開一層;第四個參數(shù)表示 input 展開的起始位置,即從 input 數(shù)組中第幾個元素開始展開。
var ans = flatten([[1, 2], [3, 4]], false, false, 1); console.log(ans); // => [3, 4]
從第 1 項(xiàng)開始展開數(shù)組,即忽略了數(shù)組的第 0 項(xiàng)([1, 2])。
以上三個參數(shù)還是比較容易理解的,相對來說費(fèi)勁的是第三個參數(shù) strict。strict 也是個布爾值,當(dāng) shallow 為 true 并且 strict 也為 true 時,能過濾 input 參數(shù)元素中的非數(shù)組元素。好難理解啊!我們舉個簡單的例子。
var ans = flatten([5, 6, [1, 2], [3, 4]], true, true); console.log(ans); // => [1, 2, 3, 4]
5 和 6 是 input 參數(shù)中的非數(shù)組元素,直接過濾掉了。如果 strict 為 true 并且 shallow 為 false,那么調(diào)用 flatten 方法的結(jié)果只能是 []。所以我們會看到源碼里如果 strict 為 true,那么 shallow 也一定是 true。
直接來看源碼,加了非常多的注釋。
var flatten = function(input, shallow, strict, startIndex) { // output 數(shù)組保存結(jié)果 // 即 flatten 方法返回?cái)?shù)據(jù) // idx 為 output 的累計(jì)數(shù)組下標(biāo) var output = [], idx = 0; // 根據(jù) startIndex 變量確定需要展開的起始位置 for (var i = startIndex || 0, length = getLength(input); i < length; i++) { var value = input[i]; // 數(shù)組 或者 arguments if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { // flatten current level of array or arguments object // (!shallow === true) => (shallow === false) // 則表示需深度展開 // 繼續(xù)遞歸展開 if (!shallow) // flatten 方法返回?cái)?shù)組 // 將上面定義的 value 重新賦值 value = flatten(value, shallow, strict); // 遞歸展開到最后一層(沒有嵌套的數(shù)組了) // 或者 (shallow === true) => 只展開一層 // value 值肯定是一個數(shù)組 var j = 0, len = value.length; // 這一步貌似沒有必要 // 畢竟 JavaScript 的數(shù)組會自動擴(kuò)充 // 但是這樣寫,感覺比較好,對于元素的 push 過程有個比較清晰的認(rèn)識 output.length += len; // 將 value 數(shù)組的元素添加到 output 數(shù)組中 while (j < len) { output[idx++] = value[j++]; } } else if (!strict) { // (!strict === true) => (strict === false) // 如果是深度展開,即 shallow 參數(shù)為 false // 那么當(dāng)最后 value 不是數(shù)組,是基本類型時 // 肯定會走到這個 else-if 判斷中 // 而如果此時 strict 為 true,則不能跳到這個分支內(nèi)部 // 所以 shallow === false 如果和 strict === true 搭配 // 調(diào)用 flatten 方法得到的結(jié)果永遠(yuǎn)是空數(shù)組 [] output[idx++] = value; } } return output; };
總的來說,就是持續(xù)遞歸調(diào)用 flatten,直到不能展開為止。給出 flatten 方法的實(shí)現(xiàn)源碼位置 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L489-L507。
接著我們來看看源碼中有用到這個內(nèi)部方法的 API。
首先是 _.flatten 方法,非常簡單,用了 flatten 的前三個參數(shù)。
_.flatten = function(array, shallow) { // array => 需要展開的數(shù)組 // shallow => 是否只展開一層 // false 為 flatten 方法 strict 變量 return flatten(array, shallow, false); };
前面說了,strict 為 true 只和 shallow 為 true 一起使用,所以沒有特殊情況的話 strict 默認(rèn)為 false。
_.union 方法同樣用到了 flatten,這個方法的作用是傳入多個數(shù)組,然后對數(shù)組元素去重。
var ans = _.union([[1]], [1, 2], 3, 4); console.log(ans); // => [[1], 1, 2]
首先并不需要對數(shù)組深度展開,其次 _.union 傳入的是數(shù)組,對于非數(shù)組元素可以直接忽略。這兩點(diǎn)直接對應(yīng)了 shallow 參數(shù)和 strict 參數(shù)均為 true(都不用做容錯處理了)。對于一個數(shù)組的去重,最后調(diào)用 _.unique 即可。
_.union = function() { // 首先用 flatten 方法將傳入的數(shù)組展開成一個數(shù)組 // 然后就可以愉快地調(diào)用 _.uniq 方法了 // 假設(shè) _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); // arguments 為 [[1, 2, 3], [101, 2, 1, 10], [2, 1]] // shallow 參數(shù)為 true,展開一層 // 結(jié)果為 [1, 2, 3, 101, 2, 1, 10, 2, 1] // 然后對其去重 return _.uniq(flatten(arguments, true, true)); };
而 _.difference,_.pick,_.omit 方法,大家可以自己進(jìn)源碼去看,都大同小異,沒什么特別要注意的點(diǎn)。(注意下 startIndex 參數(shù)即可)
對于內(nèi)部方法 flatten,我要總結(jié)的是,可能某個內(nèi)部方法會被多個 API 調(diào)用,如何設(shè)計(jì)地合理,優(yōu)雅,如何兼顧到各種情況,真的需要強(qiáng)大的實(shí)踐以及代碼能力,這點(diǎn)還需要日后多加摸索。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86357.html
摘要:原文地址數(shù)組展開就是將嵌套的數(shù)組扁平化轉(zhuǎn)換為一維的判斷每一項(xiàng)是否是數(shù)組,然后遞歸遞歸調(diào)用數(shù)組在調(diào)用會將數(shù)組轉(zhuǎn)換成再執(zhí)行方法會變成還需要將所有的參數(shù)轉(zhuǎn)換為數(shù)字,所以這種方式的不足就是如果數(shù)組里面是既有數(shù)字又有字符串,會全部展開為數(shù)字轉(zhuǎn)為數(shù)字方 原文地址 數(shù)組展開就是將嵌套的數(shù)組扁平化(轉(zhuǎn)換為一維的)eg: const arr=[[[1, 2], [1, 2, 3]], [1, 2]] ...
摘要:直接來看例子一目了然,第一個參數(shù)是對象,第二個參數(shù)可以是一系列的值,也可以是數(shù)組數(shù)組中含,也可以是迭代函數(shù),我們根據(jù)值,或者迭代函數(shù)來過濾中的鍵值對,返回新的對象副本。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中。 閱讀一些著名框架類庫的源碼,就好像和一個個大師對話,你會學(xué)到很多。...
摘要:而這個秒就能理解的代碼片段,摒棄了許多不必要的代碼,只實(shí)現(xiàn)了最核心的部分,不像和那樣,考慮參數(shù)邊界值問題,例如,參數(shù)的類型是否符合預(yù)期等。使用根據(jù)斷言函數(shù)對數(shù)組進(jìn)行過濾,返回條件為真值的對象。 之前翻譯過一篇文章,《我喜歡的5個編程技巧》,里面的一個技巧是借鑒一個網(wǎng)站的代碼片段,好奇的小手點(diǎn)下鏈接后,發(fā)現(xiàn)是一個有 47000 多star的倉庫,30-seconds-of-code。 倉...
摘要:最近開始看源碼,并將源碼解讀放在了我的計(jì)劃中。將轉(zhuǎn)為數(shù)組同時去掉第一個元素之后便可以調(diào)用方法總結(jié)數(shù)組的擴(kuò)展方法就解讀到這里了,相關(guān)源碼可以參考這部分。放個預(yù)告,下一篇會暫緩下,講下相關(guān)的東西,敬請期待。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中。 閱讀一些著名框架類庫的源碼,就好...
摘要:專題系列第九篇,講解如何實(shí)現(xiàn)數(shù)組的扁平化,并解析的源碼扁平化數(shù)組的扁平化,就是將一個嵌套多層的數(shù)組嵌套可以是任何層數(shù)轉(zhuǎn)換為只有一層的數(shù)組。 JavaScript 專題系列第九篇,講解如何實(shí)現(xiàn)數(shù)組的扁平化,并解析 underscore 的 _.flatten 源碼 扁平化 數(shù)組的扁平化,就是將一個嵌套多層的數(shù)組 array (嵌套可以是任何層數(shù))轉(zhuǎn)換為只有一層的數(shù)組。 舉個例子,假設(shè)有個...
閱讀 2763·2021-09-24 09:47
閱讀 4382·2021-08-27 13:10
閱讀 3032·2019-08-30 15:44
閱讀 1302·2019-08-29 12:56
閱讀 2605·2019-08-28 18:07
閱讀 2627·2019-08-26 14:05
閱讀 2587·2019-08-26 13:41
閱讀 1278·2019-08-26 13:33