詳解lodash中的cloneDeep使用細(xì)節(jié)
正文
lodash中的cloneDeep是一個(gè)使用頻率比較高的方法,然而你真的理解其中的細(xì)節(jié)處理嗎?如果下面幾個(gè)問(wèn)題你還有疑惑那么本文對(duì)你或多或少有些幫助。
- cloneDeep中支持拷貝函數(shù)、Error對(duì)象、DOM節(jié)點(diǎn)以及WeakMap對(duì)象嗎?
- cloneDeep中使用了哪種算法呢?
- 瀏覽器中提供的實(shí)現(xiàn)深拷貝的方式除了JSON.parse(JSON.stringify()),還有其他方法嗎?
- 當(dāng)遇到循環(huán)引用時(shí),如何進(jìn)行深拷貝操作來(lái)避免出現(xiàn)棧溢出呢?
當(dāng)上面這些問(wèn)題你還有疑惑時(shí),可能會(huì)在一些比較少見(jiàn)的場(chǎng)景中遇到一些出乎意料的問(wèn)題,希望本文能夠?qū)δ阌兴鶐椭?/p>
支持的數(shù)據(jù)類(lèi)型
lodash中支持了很多種的數(shù)據(jù)類(lèi)型,包括 arrays、array buffers、 booleans、 date objects、maps、 numbers、Object、regexes、sets、 strings、symbols、typed arrays,以及包括arguments這個(gè)參數(shù)(不過(guò)拷貝后會(huì)丟失一些信息)。
但是由于一些原因,還有一些類(lèi)型,lodash中默認(rèn)時(shí)不支持的。至于error objects、functions、DOM nodes、以及WeakMaps默認(rèn)是不支持的,lodash默認(rèn)會(huì)返回一個(gè)控對(duì)象,所以如果數(shù)據(jù)中存在這些數(shù)據(jù)類(lèi)型時(shí)需要特別關(guān)注一下,拷貝之后就無(wú)法獲取對(duì)應(yīng)的數(shù)據(jù)了。
cloneDeepWith
如果拷貝的數(shù)據(jù)中存在不支持的數(shù)據(jù)類(lèi)型時(shí),我們改怎么辦呢?
lodash為我們提供了另外一個(gè)方法,與cloneDeep比較類(lèi)似,只不過(guò)我們可以在這個(gè)方法中傳入一個(gè)自定義函數(shù),當(dāng)遇到不支持的數(shù)據(jù)類(lèi)型時(shí),我們可以根據(jù)場(chǎng)景來(lái)定義自己的深拷貝的實(shí)現(xiàn)邏輯。比如說(shuō)當(dāng)拷貝函數(shù)時(shí),返回函數(shù)本身等。
lodash官網(wǎng) 有著比較詳細(xì)的例子,也可以參考一下。
拷貝算法介紹
lodash作為一個(gè)使用非常廣泛的庫(kù),在拷貝算法上使用了structured clone algorithm,這個(gè)算法細(xì)節(jié)描述可以參考 html.spec.whatwg.org/multipage/s… ,與目前瀏覽器中的structuredClone方法實(shí)現(xiàn)采用的是一樣的算法,在其他一些場(chǎng)景中大家進(jìn)行拷貝方式的實(shí)現(xiàn)基本是一致的,這也保證了使用cloneDeep方法具有良好的兼容性。
structuredClone VS cloneDeep
目前瀏覽器中提供了structuredClone 方法來(lái)處理需要深拷貝的場(chǎng)景,那我們還需要使用lodash提供的cloneDeep方法嗎?從目前來(lái)看這個(gè)API在web場(chǎng)景的兼容性:

目前看來(lái)兼容性還不是特別高,大家可以根據(jù)自己的場(chǎng)景來(lái)進(jìn)行選用,畢竟使用lodash會(huì)增加包體積大小,對(duì)于一些追求極致性能的場(chǎng)景包體積肯定越小越好。
循環(huán)引用處理方法
在處理拷貝過(guò)程中一般都會(huì)遇到一個(gè)比較棘手的問(wèn)題:循環(huán)引用, 看下面這段簡(jiǎn)單的代碼:
const objb = {
b: null
};
const obja = {
a: objb
};
objb.b = obja;
console.log(objb);在控制臺(tái)中輸出objb對(duì)象,展開(kāi)其屬性,我們可以看到這個(gè)結(jié)果:

可以看到objb對(duì)象的屬性可以無(wú)限展開(kāi)下去,這樣就形成了循環(huán)引用。形成循環(huán)引用的原因就是,objb.b引用了obja對(duì)象;但是obja.a屬性又引用了objb對(duì)象。

如果我們進(jìn)行不斷的拷貝而不做針對(duì)循環(huán)引用的處理,必然會(huì)出現(xiàn)這個(gè)錯(cuò)誤:

那么lodash中是如何處理這個(gè)問(wèn)題的呢?
其實(shí)lodash中處理循環(huán)引用的方法非常簡(jiǎn)單清晰,下面這段代碼是處理循環(huán)引用的核心代碼??梢钥闯鰈odash中主要通過(guò)緩存每個(gè)值對(duì)應(yīng)的拷貝結(jié)果來(lái)解決循環(huán)引用的問(wèn)題。

針對(duì)上面的這個(gè)存在循環(huán)引用的對(duì)象,我們可以來(lái)按步驟進(jìn)行分析一下cloneDeep(objb)時(shí)是如何解決循環(huán)引用的:
- 處理objb對(duì)象,stack.get(objb)不存在,所以將代表objb的拷貝結(jié)果result放到stack中,然后逐個(gè)處理objb上的屬性
- 處理objb中的b屬性,stack.get(obj.b)其實(shí)也就是stack.get(obja),此時(shí)stacka也在stack中,因此也將代表obja的拷貝結(jié)果result放置到stack中,然后逐個(gè)處理obja上的屬性
- 處理obja上的a屬性,stack.get(obja.a)其實(shí)也就是stack.get(objb),經(jīng)過(guò)前兩步的處理,我們只在此時(shí),objb已經(jīng)存在stack中了,stack.get(objb)返回一個(gè)拷貝后的對(duì)象
拷貝過(guò)程結(jié)束,返回拷貝的結(jié)果 可以結(jié)合下面這幅圖來(lái)進(jìn)行理解:

總結(jié)
深拷貝看起來(lái)簡(jiǎn)單,但是實(shí)現(xiàn)中有很多細(xì)節(jié)需要注意,lodash這類(lèi)工具庫(kù)確實(shí)幫我們解決了不少問(wèn)題,感謝開(kāi)源!
以上就是詳解lodash中的cloneDeep使用細(xì)節(jié)的詳細(xì)內(nèi)容,更多關(guān)于lodash cloneDeep使用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序 switch組件詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了微信小程序 switch組件詳解及簡(jiǎn)單實(shí)例 的相關(guān)資料,需要的朋友可以參考下2017-01-01
JavaScript嚴(yán)格模式不支持八進(jìn)制的問(wèn)題講解
這篇文章主要講解JavaScript嚴(yán)格模式不支持八進(jìn)制的問(wèn)題,本文圍繞JavaScript嚴(yán)格模式展開(kāi)內(nèi)容,詳細(xì)介紹為什么JavaScript嚴(yán)格模式不支持八進(jìn)制,下面來(lái)看看詳細(xì)介紹,需要的朋友可以參考一下2021-11-11
微信小程序 彈框和模態(tài)框?qū)崿F(xiàn)代碼
這篇文章主要介紹了微信小程序 彈框和模態(tài)框?qū)崿F(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03
package.json中browser?module?main字段優(yōu)先級(jí)對(duì)比
這篇文章主要介紹了package.json中browser?module?main字段的優(yōu)先級(jí)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Astro Islands靜態(tài)頁(yè)面交互式UI組件
這篇文章主要為大家介紹了Astro Islands靜態(tài)頁(yè)面交互式UI組件使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Wireshark基本介紹和學(xué)習(xí)TCP三次握手
本文主要介紹Wireshark基本介紹和學(xué)習(xí)TCP三次握手,這里詳細(xì)整理了相關(guān)資料,并給出詳細(xì)流程,有需要的小伙伴可以參考下2016-08-08

