摘要:依賴源碼分析之緩存使用方式的進(jìn)一步封裝源碼分析之源碼分析之源碼分析之的實(shí)現(xiàn)源碼分析之源碼分析的調(diào)用如果有傳遞,則先調(diào)用,使用生成要比較數(shù)組的映射數(shù)組。循環(huán)完畢,沒(méi)有在第二個(gè)數(shù)組中發(fā)現(xiàn)相同的項(xiàng)時(shí),將該項(xiàng)存入數(shù)組中。
外部世界那些破舊與貧困的樣子,可以使我內(nèi)心世界得到平衡。——卡爾維諾《煙云》
本文為讀 lodash 源碼的第十七篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-lodash
gitbook也會(huì)同步倉(cāng)庫(kù)的更新,gitbook地址:pocket-lodash
作用與用法baseDifference 可以用來(lái)獲取指定數(shù)組與另一個(gè)數(shù)組的差集。
這個(gè)函數(shù)是內(nèi)部函數(shù),是后面實(shí)現(xiàn)其它比較函數(shù)的核心函數(shù)。
baseDifference 的方法簽名如下:
baseDifference(array, values, iteratee, comparator)
第一和第二個(gè)參數(shù)是需要比較的兩個(gè)數(shù)組;iteratee 可以返回一值映射值,比較時(shí),可以使用映射的值來(lái)進(jìn)行比較; comparator 是自定義比較函數(shù),如果有傳遞,則調(diào)用自定義的比較函數(shù)來(lái)進(jìn)行交集的比較。
依賴import SetCache from "./SetCache.js" import arrayIncludes from "./arrayIncludes.js" import arrayIncludesWith from "./arrayIncludesWith.js" import map from "../map.js" import cacheHas from "./cacheHas.js"
lodash源碼分析之緩存使用方式的進(jìn)一步封裝
lodash源碼分析之a(chǎn)rrayIncludes
lodash源碼分析之a(chǎn)rrayIncludesWith
lodash源碼分析之map的實(shí)現(xiàn)
lodash源碼分析之cacheHas
源碼分析const LARGE_ARRAY_SIZE = 200 function baseDifference(array, values, iteratee, comparator) { let includes = arrayIncludes let isCommon = true const result = [] const valuesLength = values.length if (!array.length) { return result } if (iteratee) { values = map(values, (value) => iteratee(value)) } if (comparator) { includes = arrayIncludesWith isCommon = false } else if (values.length >= LARGE_ARRAY_SIZE) { includes = cacheHas isCommon = false values = new SetCache(values) } outer: for (let value of array) { const computed = iteratee == null ? value : iteratee(value) value = (comparator || value !== 0) ? value : 0 if (isCommon && computed === computed) { let valuesIndex = valuesLength while (valuesIndex--) { if (values[valuesIndex] === computed) { continue outer } } result.push(value) } else if (!includes(values, computed, comparator)) { result.push(value) } } return result }iteratee的調(diào)用
if (iteratee) { values = map(values, (value) => iteratee(value)) }
如果有傳遞 iteratee ,則先調(diào)用 map ,使用 iteratee 生成要比較數(shù)組的映射數(shù)組 values。
因?yàn)楹竺鏁?huì)有嵌套循環(huán),避免重復(fù)調(diào)用 iteratee ,影響性能,所以一開(kāi)始就需要生成 values 的映射數(shù)組。
性能優(yōu)化這里使用了 isCommon 來(lái)標(biāo)志是否使用普通方式來(lái)處理。
if (comparator) { includes = arrayIncludesWith isCommon = false }
如果有傳遞比較函數(shù),則將 isCommon 標(biāo)記為 false,表示不用普通的方式來(lái)處理,后面可以看到,最后會(huì)使用 includes 方法來(lái)處理,也即 arrayIncludesWith 方法。
else if (values.length >= LARGE_ARRAY_SIZE) { includes = cacheHas isCommon = false values = new SetCache(values) }
如果不需要使用自定義的比較方式,并且數(shù)組較大時(shí)(這里限定了200),則使用 SetCache 類(lèi)來(lái)緩存數(shù)組。
SetChche 其實(shí)使用的是 Map/Set 或者對(duì)象的方式來(lái)存儲(chǔ),避免大數(shù)組嵌套循環(huán)時(shí)造成的性能損耗。
### 循環(huán)比較
接下來(lái)就遍歷第一個(gè)數(shù)組 array,將數(shù)組中的每一項(xiàng)和第二個(gè)數(shù)組的每一項(xiàng)比較。
if (isCommon && computed === computed) { let valuesIndex = valuesLength while (valuesIndex--) { if (values[valuesIndex] === computed) { continue outer } } result.push(value) } else if (!includes(values, computed, comparator)) { result.push(value) }
可以看到,如果 isCommon 沒(méi)有標(biāo)記為 false, 或者需要比較的值 computed 不為 NaN 時(shí),都采用嵌套循環(huán)的方式來(lái)比較。循環(huán)完畢,沒(méi)有在第二個(gè)數(shù)組中發(fā)現(xiàn)相同的項(xiàng)時(shí),將該項(xiàng)存入數(shù)組 result 中。
如果 isCommon 為 false 或者需要比較的值為 NaN 時(shí),則調(diào)用 includes 方法來(lái)比較。
由之前的分析得知:
如果指定 comparator ,則 includes 為 arrayIncludesWith
如果被比較的數(shù)組 values 的長(zhǎng)度超過(guò) 200 ,則 includes 為 cacheHas
否則,includes 為 arrayIncludes
+0與-0的處理在看代碼的時(shí)候,有一段十分奇怪:
value = (comparator || value !== 0) ? value : 0
這段代碼的意思是,在沒(méi)有提供 comparator 的情況下,如果 value === 0 ,則將 value 賦值為 0 。
value === 0 時(shí),可能為 +0 、-0 和 0 ,lodash 為什么要將它們都轉(zhuǎn)為 0 呢?
后來(lái)看到 lodash 作者在 issue 中說(shuō),因?yàn)楸容^會(huì)用到 Set ,而 Set 是不能區(qū)分 +0 和 -0 的。
參考Lodash系列——difference函數(shù)源碼解析
value = (comparator || value !== 0) ? value : 0; does it work?
License署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際 (CC BY-NC-ND 4.0)
最后,所有文章都會(huì)同步發(fā)送到微信公眾號(hào)上,歡迎關(guān)注,歡迎提意見(jiàn):
作者:對(duì)角另一面
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93421.html
摘要:但是在類(lèi)中,要初始化緩存和設(shè)置緩存都需要提供和組成的二維數(shù)組,因此在類(lèi)中,提供了一種更方便的緩存設(shè)置方式,只需要提供緩存的值即可。這里構(gòu)造函數(shù)不需要再傳入的二維數(shù)組了,只需要傳入包含所有緩存值的數(shù)組即可。 在世界上所有的民族之中,支配著他們的喜怒選擇的并不是天性,而是他們的觀點(diǎn)。——盧梭《社會(huì)與契約論》 本文為讀 lodash 源碼的第九篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star...
摘要:但是在類(lèi)中,要初始化緩存和設(shè)置緩存都需要提供和組成的二維數(shù)組,因此在類(lèi)中,提供了一種更方便的緩存設(shè)置方式,只需要提供緩存的值即可。這里構(gòu)造函數(shù)不需要再傳入的二維數(shù)組了,只需要傳入包含所有緩存值的數(shù)組即可。 在世界上所有的民族之中,支配著他們的喜怒選擇的并不是天性,而是他們的觀點(diǎn)?!R梭《社會(huì)與契約論》 本文為讀 lodash 源碼的第九篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star...
摘要:萬(wàn)條數(shù)據(jù)依賴讀源碼之從看稀疏數(shù)組與密集數(shù)組原理的原理歸結(jié)起來(lái)就是切割和放置。尺在切割之前,需要用尺確定切割的數(shù)量。容器的長(zhǎng)度剛好與塊的數(shù)量一致。當(dāng)與塊的數(shù)量相等時(shí),表示已經(jīng)切割完畢,停止切割,最后將結(jié)果返回。 以不正義開(kāi)始的事情,必須用罪惡使它鞏固?!勘葋啞尔溈税住? 最近很多事似乎印證了這句話,一句謊言最后要用一百句謊言來(lái)圓謊。 本文為讀 lodash 源碼的第二篇,后續(xù)文章會(huì)...
摘要:作用與用法是的內(nèi)部函數(shù),之前在源碼分析之緩存介紹過(guò)一種這樣的數(shù)據(jù)結(jié)構(gòu)這是一個(gè)二維數(shù)組,每項(xiàng)中的第一項(xiàng)作為緩存對(duì)象的,第二項(xiàng)為緩存的值。 這個(gè)世界需要一個(gè)特定的惡人,可以供人們指名道姓,千夫所指:全都怪你?!迳洗簶?shù)《當(dāng)我談跑步時(shí)我談些什么》 本文為讀 lodash 源碼的第六篇,后續(xù)文章會(huì)更新到這個(gè)倉(cāng)庫(kù)中,歡迎 star:pocket-lodash gitbook也會(huì)同步倉(cāng)庫(kù)的更新...
摘要:在之前的文章中已經(jīng)介紹過(guò),檢測(cè)的是對(duì)應(yīng)的數(shù)組在二維數(shù)組中的索引,其行為跟一致,不存在于二維數(shù)組中時(shí),返回,否則返回索引值。最后將緩存數(shù)量減少。 昨日我沿著河岸/漫步到/蘆葦彎腰喝水的地方順便請(qǐng)煙囪/在天空為我寫(xiě)一封長(zhǎng)長(zhǎng)的信 潦是潦草了些/而我的心意/則明亮亦如你窗前的燭光/稍有曖昧之處/勢(shì)所難免/因?yàn)轱L(fēng)的緣故 ——洛夫《因?yàn)轱L(fēng)的緣故》 本文為讀 lodash 源碼的第七篇,后續(xù)文章會(huì)...
閱讀 1083·2021-11-22 15:35
閱讀 1723·2021-10-26 09:49
閱讀 3266·2021-09-02 15:11
閱讀 2105·2019-08-30 15:53
閱讀 2659·2019-08-30 15:53
閱讀 2955·2019-08-30 14:11
閱讀 3550·2019-08-30 12:59
閱讀 3268·2019-08-30 12:53