国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > JS > 正文

JavaScript深度復(fù)制(deep clone)的實現(xiàn)方法

2024-05-06 16:28:44
字體:
供稿:網(wǎng)友
本文給大家介紹JavaScript深度復(fù)制(deep clone)的實現(xiàn)方法,涉及到j(luò)s深度復(fù)制相關(guān)知識,本文介紹的非常詳細(xì),特此分享VeVb武林網(wǎng)平臺供大家參考
 

在代碼復(fù)用模式里面有一種叫做“復(fù)制屬性模式”(copying properties pattern)。談到代碼復(fù)用的時候,很有可能想到的是代碼的繼承性(inheritance),但重要的是要記住其最終目標(biāo)——我們要復(fù)用代碼。繼承性只是實現(xiàn)代碼復(fù)用的一種手段,而不是唯一的方法。復(fù)制屬性也是一種復(fù)用模式,它跟繼承性是有所不同的。這種模式中,對象將從另外一個在對象中獲取成員,其方法是僅需將其復(fù)制即可。用過jQuery的都知道,它有一個$.extend()方法,它的用途除了擴展第三方插件之外,還可以用來復(fù)制屬性的。下面我們來看一個extend()函數(shù)的實現(xiàn)代碼(注意這里的并不是jQuery的源碼,只是一個簡單的示例):

function extend(parent, child) {var i;//如果不傳入第二參數(shù)child//那么就創(chuàng)建一個新的對象child = child || {}; //遍歷parent對象的所有屬性//并且過濾原型上的屬性//然后將自身屬性復(fù)制到child對象上for(i in parent) {if(parent.hasOwnProperty(i)) {child[i] = parent[i];}}//返回目標(biāo)對象childreturn child;} 

上面的代碼是一個簡單的實現(xiàn),它僅遍歷父對象的成員并將其復(fù)制到子對象中去。下面我們用上面的extend()方法來測試一下:

var dad = {name: "Adam"};var kid = extend(dad);console.log(kid.name); //Adam 

我們發(fā)現(xiàn),extend()方法已經(jīng)可以正常工作了。但是有一個問題,上面給出的是一種所謂的淺復(fù)制(shallow clone)。在使用淺復(fù)制的時候,如果改變了子對象的屬性,并且該屬性恰好又是一個對象,那么這種操作也會修改父對象,單是很多情況這不是我們想要的結(jié)果。考慮下列情況:

var dad = {counts: [1, 2, 3],reads: {paper: true}};var kid = extend(dad) //調(diào)用extend()方法將dad的屬性復(fù)制到kid上面kid.counts.push(4); //把4追加到kid.counts數(shù)組里面console.log(dad.counts); //[1, 2, 3, 4] 

通過上面的例子,我們會發(fā)現(xiàn),修改了kid.counts屬性以后(把元素4追加進(jìn)去了),dad.counts也會受到影響。這是因為在使用淺復(fù)制的時候,由于對象是通過引用傳遞的,即kid.counts和dad.counts指向的是同一個數(shù)組(或者說在內(nèi)存上他們指向同一個堆的地址)。

下面,讓我們修改extend()函數(shù)以實現(xiàn)深度復(fù)制。我們需要做的事情就是檢查父對象的每一個屬性,如果該屬性恰好是對象的話,那么就遞歸復(fù)制出該對象的屬性。另外,還需要檢測該對象是否為一個數(shù)組,這是因為數(shù)組的字面量創(chuàng)建方式和對象的字面量創(chuàng)建方式不一樣,前者是[],后者是{}。檢測數(shù)組可以使用Object.prototype.toString()方法進(jìn)行檢測,如果是數(shù)組的話,他會返回"[object Array]"。下面我們來看一下深度復(fù)制版本的extend()函數(shù):

function extendDeep(parent, child) {child = child || {};for(var i in parent) {if(parent.hasOwnProperty(i)) {//檢測當(dāng)前屬性是否為對象if(typeof parent[i] === "object") {//如果當(dāng)前屬性為對象,還要檢測它是否為數(shù)組//這是因為數(shù)組的字面量表示和對象的字面量表示不同//前者是[],而后者是{}child[i] = (Object.prototype.toString.call(parent[i]) === "[object Array]") ? [] : {};//遞歸調(diào)用extendextendDeep(parent[i], child[i]);} else {child[i] = parent[i];}}}return child;} 

好了,深度復(fù)制的函數(shù)已經(jīng)寫好了,下面來測試一下看是否能夠預(yù)期那樣子工作,即是否可以實現(xiàn)深度復(fù)制:

var dad = {counts: [1, 2, 3],reads: {paper: true}};var kid = extendDeep(dad);//修改kid的counts屬性和reads屬性kid.counts.push(4);kid.reads.paper = false;console.log(kid.counts); //[1, 2, 3, 4]console.log(kid.reads.paper); //falseconsole.log(dad.counts); //[1, 2, 3]console.log(dad.reads.paper); //true 

通過上面例子,我們可以發(fā)現(xiàn),即使修改了子對象的kid.counts和kid.reads,父對象的dad.counts和kid.reads并沒有改變,因此我們的目的實現(xiàn)了。

下面來總結(jié)一下實現(xiàn)深復(fù)制的的基本思路:

1.檢測當(dāng)前屬性是否為對象

2.因為數(shù)組是特殊的對象,所以,在屬性為對象的前提下還需要檢測它是否為數(shù)組。

3.如果是數(shù)組,則創(chuàng)建一個[]空數(shù)組,否則,創(chuàng)建一個{}空對象,并賦值給子對象的當(dāng)前屬性。然后,遞歸調(diào)用extendDeep函數(shù)。

上面例子使我們自己使用遞歸算法實現(xiàn)的一種深度復(fù)制方法。事實上,ES5新增的JSON對象提供的兩個方法也可以實現(xiàn)深度復(fù)制,分別是JSON.stringify()和JSON.parse();前者用來將對象轉(zhuǎn)成字符串,后者則把字符串轉(zhuǎn)換成對象。下面我們使用該方法來實現(xiàn)一個深度復(fù)制的函數(shù):

function extendDeep(parent, child) {var i,proxy;proxy = JSON.stringify(parent); //把parent對象轉(zhuǎn)換成字符串proxy = JSON.parse(proxy) //把字符串轉(zhuǎn)換成對象,這是parent的一個副本child = child || {};for(i in proxy) {if(proxy.hasOwnProperty(i)) {child[i] = proxy[i];}}proxy = null; //因為proxy是中間對象,可以將它回收掉return child;} 

下面是測試?yán)樱?/p>

var dad = {counts: [1, 2, 3],reads: {paper: true}};var kid = extendDeep(dad);//修改kid的counts屬性和reads屬性kid.counts.push(4);kid.reads.paper = false;console.log(kid.counts); //[1, 2, 3, 4]console.log(kid.reads.paper); //falseconsole.log(dad.counts); //[1, 2, 3]console.log(dad.reads.paper); //true 

測試發(fā)現(xiàn),它也實現(xiàn)了深度復(fù)制。一般推薦使用后面這種方法,因為JSON.parse和JSON.stringify是內(nèi)置函數(shù),處理起來會比較快。另外,前面的那種方法使用了遞歸調(diào)用,我們都知道,遞歸是效率比較低的一種算法。

關(guān)于JavaScript深度復(fù)制(deep clone)的實現(xiàn)方法就給大家介紹這么多,希望對大家有所幫助!



注:相關(guān)教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 儋州市| 五家渠市| 宁南县| 繁峙县| 老河口市| 娄烦县| 伊通| 南华县| 开化县| 五寨县| 开封县| 桓仁| 当涂县| 常德市| 乌海市| 同江市| 松溪县| 信宜市| 碌曲县| 东安县| 嵊州市| 凤城市| 绥滨县| 灵武市| 新密市| 湖南省| 汤阴县| 略阳县| 信阳市| 安阳市| 荣成市| 永兴县| 竹山县| 冀州市| 寻乌县| 鹰潭市| 筠连县| 神池县| 山西省| 青田县| 青田县|