0x001前言
?????????在前端中弱睦,我們都知道百姓,數(shù)組和對象是引用傳遞,正是因?yàn)檫@一特性是存在况木,讓我們又喜又憂垒拢。喜:喜在我們可以將結(jié)構(gòu)復(fù)雜的數(shù)據(jù)進(jìn)行拆解修改旬迹。憂:憂在數(shù)據(jù)復(fù)制的時(shí)候,擺脫耦合性和相關(guān)度是很麻煩的求类。為此奔垦,我們需要人為的增加一些方法,去復(fù)制引用類型的數(shù)據(jù)尸疆,在這里椿猎,我們優(yōu)雅的稱這種復(fù)制的手段叫做:克隆(clone)寿弱。
? ? ? ? 寫一個(gè)克隆函數(shù),幾乎是所有前端學(xué)習(xí)者的必經(jīng)之路症革,我們現(xiàn)在來好好討論一下筐咧,你,曾經(jīng)寫過的克隆噪矛,都有什么問題量蕊,到底,有沒有一個(gè)完美的克隆方案艇挨?讀者別急残炮,我們慢慢往下看。
0x002淺度克隆
? ? ? ? 淺度克隆雷袋,也是最簡單的克隆吉殃,同時(shí)也是缺陷最明顯的克隆方案,我們先來看一個(gè)最簡單的淺度克驴(又叫:淺克碌吧住)案例:
? ? ? ? 我們可以看出,這個(gè)版本的淺克隆方案就是把要克隆的數(shù)據(jù)遍歷一遍鸠删,然后賦值抱完,返回,這樣寫確實(shí)可以避免一定相關(guān)性刃泡,但是如果數(shù)據(jù)里面依然是引用類型呢巧娱?那不就失效了嗎,因?yàn)闇\克隆只克隆了第一層(我們稱為原始層)烘贴。其次禁添,這個(gè)clone函數(shù)只能克隆數(shù)組和原始對象,對于構(gòu)造函數(shù)構(gòu)造出的對象桨踪,克隆結(jié)果會(huì)變成原始對象老翘,數(shù)據(jù)就不是一種類型了,這也是我們不想要的,這個(gè)問題我們暫時(shí)稱它:原型失配問題
? ? ? ? 從這個(gè)例子我們可以清晰的看出克隆出來的b和之前的a完全不是一個(gè)數(shù)據(jù)種類铺峭,那么能否解決它呢墓怀?或者該如何解決呢?我們可以嘗試使用虛擬構(gòu)造來得出一個(gè)同類型的數(shù)據(jù)體卫键,然后再正常的一一克隆傀履,如下圖所示:
? ? ? ? 細(xì)心的朋友應(yīng)該發(fā)現(xiàn)了,雖然構(gòu)造后大體都很相似了莉炉,但是控制臺(tái)的類型標(biāo)注還是明顯區(qū)分出了Foo和F钓账,這個(gè)問題,還真沒有太好的方法去解決呢袱,但是官扣,對于數(shù)據(jù)體達(dá)到一樣后,我們可以近似的認(rèn)為他們是同類型構(gòu)造體羞福,而且再他們的construct中惕蹄,也是相同的函數(shù)。至此治专,淺克隆基本上完成卖陵,接下來就要解決淺克隆的不能深層次的克隆問題。
0x003深度克隆和它的嚴(yán)重問題
? ? ? ? 解決淺克隆不能深層克隆最簡單的方式就是遍歷遞進(jìn)式的克隆张峰,也就是深度克隆泪蔫,說白了,深度克隆就是淺克隆的自我遞歸喘批,所有當(dāng)我們有一個(gè)現(xiàn)成的淺克隆撩荣,只需要對此稍加修改,就能得到普遍的深度克隆函數(shù)饶深。
? ? ? ? 可以看見餐曹,深度克隆就是在淺度克隆基礎(chǔ)上進(jìn)行了遞歸,只要判斷出是引用類型敌厘,就遞歸克隆台猴,這樣就完全消除了相關(guān)性和耦合性。到此俱两,很多人都覺得已經(jīng)沒有問題了饱狂,也可以自信的發(fā)個(gè)朋友圈炫耀下代碼了,仔細(xì)想想宪彩,看看我標(biāo)注的黑體休讳,仔細(xì)推敲一下?你會(huì)發(fā)現(xiàn)尿孔,它衍腥,其實(shí)隱藏著一個(gè)巨大的bug磺樱,就是:死循環(huán)(也叫遞歸沒有結(jié)束點(diǎn))。
0x004深度限制法去解決死循環(huán)問題
? ? ? ? ? ? ? ? 這個(gè)問題的產(chǎn)生婆咸,主要是對象源于有環(huán)對象,他們的路徑交叉后芜辕,成為環(huán)狀尚骄,為了讓我們的克隆能夠完美,就要去避免死循環(huán)侵续,第一種方法:深度限制法倔丈,就是限制最多克隆多深,我們假設(shè)再復(fù)雜的數(shù)據(jù)状蜗,對于前端而言需五,也超不出10層深度,那么我們?nèi)藶橄拗扑淖畲笊疃葹?0轧坎,當(dāng)超出后結(jié)束遞歸宏邮。顯而易見,這個(gè)方法缺點(diǎn)很明顯缸血,就是當(dāng)數(shù)據(jù)深度超過10層蜜氨,就失效了,當(dāng)然你可以讓它更深捎泻,使用場景就是你能確定你克隆數(shù)據(jù)最大深度飒炎。有點(diǎn)在于簡單,只需要對前面的深度克隆加一個(gè)深度限制就可以笆豁。
? ? ? ? 可以看見郎汪,函數(shù)中多了一個(gè)depth參數(shù),它闯狱,就是控制深度的變量煞赢,我們默認(rèn)10,你可以讓他更大扩氢。
0x005接力棒克隆
? ? ? ? 有些人耕驰,喜歡追求更完美的事物,我也一樣录豺,我不喜歡人工的方法調(diào)節(jié)它的克隆方式朦肘,我也不想知道數(shù)據(jù)深度有多深,但是双饥,我就想成功克隆有環(huán)這種惡心人的數(shù)據(jù)媒抠,為此,我嘗試了一個(gè)最笨的方法咏花,筆者給他起名叫做:接力棒克隆趴生。
? ? ? ? [由于代碼過長阀趴,我傳到的我的github,歡迎copy測試苍匆,有問題請告訴我]https://github.com/antilmid/CloneJS/blob/master/relayBarClone.js
0x006總結(jié)
? ? ? ? 每個(gè)人的思考方式不一樣刘急,解決一件事情的方法就會(huì)不一樣,上面的多種方法都為筆者所寫浸踩,但我相信叔汁,還有更多優(yōu)秀的寫法,也歡迎在評論總結(jié)检碗,從頭到尾据块,筆者總結(jié)的克隆中的種種問題,每個(gè)克隆都不是完美的折剃,至于什么克隆最好用另假,完全取決于你的數(shù)據(jù)環(huán)境。