什么是深克隆,什么是淺克隆呢?
首先,克隆只針對(duì)對(duì)象、數(shù)組、函數(shù)等復(fù)雜數(shù)據(jù)。
淺克隆就是將棧內(nèi)存中的引用復(fù)制一份,賦給一個(gè)新的變量,本質(zhì)上兩個(gè)指向堆內(nèi)存中的同一地址,內(nèi)容也相同,其中一個(gè)變化另一個(gè)內(nèi)容也會(huì)變化(根本上改變的是同一個(gè)對(duì)象)。深克隆就是創(chuàng)建一個(gè)新的空對(duì)象,開(kāi)辟一塊內(nèi)存,然后將原對(duì)象中的數(shù)據(jù)全部復(fù)制過(guò)去,完全切斷兩個(gè)對(duì)象間的聯(lián)系。
例如:
var a = new Array;
a[0] = "小明";
a[1] = "小紅";
a[2] = "小光";
b = a;
alert(b);
這里簡(jiǎn)單定義了一個(gè)數(shù)組a,然后加入三個(gè)元素,再把a(bǔ)賦給變量b,輸入b后發(fā)現(xiàn)內(nèi)容是a的內(nèi)容。這里涉及到一些內(nèi)存位置的內(nèi)容,簡(jiǎn)單說(shuō)說(shuō)。這里創(chuàng)建出的數(shù)組(array)被放在堆內(nèi)存中,而a,b兩個(gè)引用都是在棧內(nèi)存中。array包含了三個(gè)元素,a和b則僅僅是一個(gè)地址,指向了array,和C語(yǔ)言中的指針?lè)浅O嗨?。這里就是一個(gè)簡(jiǎn)單的淺克隆的例子,把數(shù)組array的引用復(fù)制一份給b,讓兩個(gè)變量都指向array。這時(shí)候任意一個(gè)引用對(duì)array做出的修改都會(huì)折射到另一個(gè)引用上。
明白了淺克隆,這里也解釋一下為什么開(kāi)始說(shuō)深淺克隆只針對(duì)對(duì)象數(shù)組函數(shù)等。先說(shuō)說(shuō)棧,棧內(nèi)存有很多優(yōu)點(diǎn),比如讀取速度很快,僅次于寄存器;棧內(nèi)存數(shù)據(jù)可以共享。但也有缺點(diǎn),棧內(nèi)存大小和生存期必須是確定的,缺乏靈活性。而因?yàn)榛咀兞浚╦s的原始值undefined,null,number,string,boolean 類(lèi)型)一般所占內(nèi)存一半較小且大小固定,所以一般放在棧中,如果放在堆中可能查找耗時(shí)較多。堆內(nèi)存中的數(shù)組、函數(shù)、對(duì)象等,一方面可能較大,另一方面不確定大小,所以不能放在棧中,只能在堆里面,由棧內(nèi)存中的句柄(也可以叫指針)加以引用操作。深淺克隆只能針對(duì)在堆內(nèi)存中的,有句柄引用的復(fù)雜對(duì)象。
深克隆本質(zhì)上是創(chuàng)造一個(gè)完全一樣的對(duì)象,這里簡(jiǎn)單介紹兩種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,不是打哪兒來(lái)回哪兒去,然后創(chuàng)建一個(gè)對(duì)象賦給result。然后遍歷arr中所有的元素,遞歸判斷是否是深層對(duì)象,不是返回賦給result。這樣就實(shí)現(xiàn)了深克隆。下面測(cè)試一下:
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"
可以看到在對(duì)原數(shù)組操作時(shí),克隆返回的數(shù)組內(nèi)容不會(huì)改變。兩個(gè)數(shù)組是完全不同的兩個(gè)對(duì)象,在堆內(nèi)存中各占一塊,沒(mé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行稍微改動(dòng)一下:
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文檔的對(duì)兩個(gè)方法的介紹,parse方法用于將字符串解析為 JSON,可以任意轉(zhuǎn)換生成的值及其屬性,并返回值。sretingify方法用于從一個(gè)對(duì)象中解析出json字符串。
意思就是將一個(gè)對(duì)象先解析為json對(duì)象,然后再解析成object對(duì)象,變來(lái)變?nèi)ロ樀绖?chuàng)建個(gè)對(duì)象完成復(fù)制。
總結(jié)
所謂深克隆就是創(chuàng)造一個(gè)完全一樣的對(duì)象,將原對(duì)象的的所有元素拷貝過(guò)來(lái)即可。
淺克隆就是復(fù)制一份引用,所有引用指向同一份數(shù)據(jù)。