什么是深克隆姓建,什么是淺克隆呢诞仓?
首先,克隆只針對對象引瀑、數(shù)組狂芋、函數(shù)等復(fù)雜數(shù)據(jù)。
淺克隆就是將棧內(nèi)存中的引用復(fù)制一份憨栽,賦給一個新的變量帜矾,本質(zhì)上兩個指向堆內(nèi)存中的同一地址,內(nèi)容也相同屑柔,其中一個變化另一個內(nèi)容也會變化(根本上改變的是同一個對象)屡萤。深克隆就是創(chuàng)建一個新的空對象,開辟一塊內(nèi)存掸宛,然后將原對象中的數(shù)據(jù)全部復(fù)制過去死陆,完全切斷兩個對象間的聯(lián)系。
例如:
var a = new Array;
a[0] = "小明";
a[1] = "小紅";
a[2] = "小光";
b = a;
alert(b);
這里簡單定義了一個數(shù)組a,然后加入三個元素措译,再把a賦給變量b别凤,輸入b后發(fā)現(xiàn)內(nèi)容是a的內(nèi)容。這里涉及到一些內(nèi)存位置的內(nèi)容领虹,簡單說說规哪。這里創(chuàng)建出的數(shù)組(array)被放在堆內(nèi)存中,而a,b兩個引用都是在棧內(nèi)存中塌衰。array包含了三個元素诉稍,a和b則僅僅是一個地址,指向了array最疆,和C語言中的指針非常相似杯巨。這里就是一個簡單的淺克隆的例子,把數(shù)組array的引用復(fù)制一份給b努酸,讓兩個變量都指向array服爷。這時候任意一個引用對array做出的修改都會折射到另一個引用上。
明白了淺克隆获诈,這里也解釋一下為什么開始說深淺克隆只針對對象數(shù)組函數(shù)等层扶。先說說棧,棧內(nèi)存有很多優(yōu)點烙荷,比如讀取速度很快,僅次于寄存器檬寂;棧內(nèi)存數(shù)據(jù)可以共享终抽。但也有缺點,棧內(nèi)存大小和生存期必須是確定的桶至,缺乏靈活性昼伴。而因為基本變量(js的原始值undefined,null,number,string,boolean 類型)一般所占內(nèi)存一半較小且大小固定,所以一般放在棧中镣屹,如果放在堆中可能查找耗時較多圃郊。堆內(nèi)存中的數(shù)組、函數(shù)女蜈、對象等持舆,一方面可能較大,另一方面不確定大小伪窖,所以不能放在棧中逸寓,只能在堆里面,由棧內(nèi)存中的句柄(也可以叫指針)加以引用操作覆山。深淺克隆只能針對在堆內(nèi)存中的竹伸,有句柄引用的復(fù)雜對象。
深克隆本質(zhì)上是創(chuàng)造一個完全一樣的對象簇宽,這里簡單介紹兩種js的deepClone方法勋篓。
一吧享、遞歸完成深克隆
例如:
function deepClone(arr) {
if (typeof arr != "object") {
return arr;
}
var result = {};
for (var i in arr) {
result[i] = deepClone(arr[i]);
}
return result;
}
首先判斷元素是否是object,不是打哪兒來回哪兒去譬嚣,然后創(chuàng)建一個對象賦給result钢颂。然后遍歷arr中所有的元素,遞歸判斷是否是深層對象孤荣,不是返回賦給result甸陌。這樣就實現(xiàn)了深克隆。下面測試一下:
var a = {
name:"小明",
age:"12",
sister:{
name:"小美",
age:"10"
}
}
var arrTwo = arrOne;
var arrThree = deepClone(a);
arrThree.name = "小光";
arrThree.object.name = "小雅";
console.log(arrTwo);
console.log(arrThree);
輸出結(jié)果:
Object:
name:"小明",
age:"12",
Object:
name:"小美",
age:"10"
Object:
name:"小光",
age:"12",
Object:
name:"小雅",
age:"10"
可以看到在對原數(shù)組操作時盐股,克隆返回的數(shù)組內(nèi)容不會改變钱豁。兩個數(shù)組是完全不同的兩個對象,在堆內(nèi)存中各占一塊疯汁,沒有關(guān)聯(lián)牲尺。
二、利用JSON
利用json就能輕松搞定:
var a = {
name:"小明",
age:"12",
sister:{
name:"小美",
age:"10"
}
}
var arrTwo = arrOne;
var arrThree = deepClone(a); //12行
arrThree.name = "小光";
arrThree.object.name = "小雅";
console.log(arrTwo);
console.log(arrThree);
把12行稍微改動一下:
var a = {
name:"小明",
age:"12",
sister:{
name:"小美",
age:"10"
}
}
var arrTwo = arrOne;
var arrThree = JSON.parse(JSON.stringify(arrTwo)); //12行
arrThree.name = "小光";
arrThree.object.name = "小雅";
console.log(arrTwo);
console.log(arrThree);
parse和stringify方法:
JSON.parse() :
Parse a string as JSON, optionally transform the produced value and its properties, and return the value.JSON.stringify() :
Return a JSON string corresponding to the specified value, optionally including only certain properties or replacing property values in a user-defined manner.
這里是摘自dash文檔的對兩個方法的介紹幌蚊,parse方法用于將字符串解析為 JSON谤碳,可以任意轉(zhuǎn)換生成的值及其屬性,并返回值溢豆。sretingify方法用于從一個對象中解析出json字符串蜒简。
意思就是將一個對象先解析為json對象,然后再解析成object對象漩仙,變來變?nèi)ロ樀绖?chuàng)建個對象完成復(fù)制搓茬。
總結(jié)
所謂深克隆就是創(chuàng)造一個完全一樣的對象,將原對象的的所有元素拷貝過來即可队他。
淺克隆就是復(fù)制一份引用卷仑,所有引用指向同一份數(shù)據(jù)。