在js中,我們經(jīng)常復(fù)制一個對象蔚叨,復(fù)制數(shù)據(jù)床蜘,那么就會有人問了,怎么復(fù)制蔑水?
JS中對象分為基本類型和復(fù)合(引用)類型邢锯,基本類型存放在棧內(nèi)存,復(fù)合(引用)類型存放在堆內(nèi)存搀别。
堆內(nèi)存用于存放由new創(chuàng)建的對象丹擎,棧內(nèi)存存放一些基本類型的變量和對象的引用變量。
至于堆內(nèi)存和棧內(nèi)存的區(qū)別介紹领曼,你們可以百度看看。
下面開始講解復(fù)制:
這種只是簡單的變量蛮穿,內(nèi)存小庶骄,我們直接復(fù)制不會發(fā)生引用。
var a=123;
var b=a;
a=123456;
alert(a); //123456
alert(b); //123
//或者是
var a='afafas';
var b=a;
a='fgfdsdsgs';
alert(a); //fgfdsdsgs
alert(b); //afafas
而對于對象這種內(nèi)存占用比較大的來說践磅,直接讓復(fù)制的東西等于要復(fù)制的单刁,那么就會發(fā)生引用,因為這種復(fù)制,只是將復(fù)制出來的東西的指向指向了要復(fù)制的那個東西羔飞,簡單的說肺樟,就是兩個都同時指向了一個空間,如果改變其中一個逻淌,另一個也會發(fā)生變化么伯。這就發(fā)生了引用。
引用只發(fā)生在對象的身上:
var arr1=[1,2,3];
var arr2=arr1;
arr1.push(4);
alert(arr1); //1234
alert(arr2); //1234
arr2.push(5);
alert(arr1); //12345
alert(arr2); //12345
那么對于數(shù)組卡儒,ES6我們復(fù)制有新的兩種方法田柔,不會發(fā)生引用。
第一種:Array.from(要復(fù)制的數(shù)組);
var arr1=[1,2,3];
var arr2=Array.from(arr1);
arr1.push(4);
alert(arr1); //1234
alert(arr2); //123
arr2.push(5);
alert(arr1); //1234
alert(arr2); //1235
第二種:...
var arr1=[1,2,3];
var arr2=[...arr1];
arr1.push(4);
alert(arr1); //1234
alert(arr2); //123
arr2.push(5);
alert(arr1); //1234
alert(arr2); //1235
第二種這個方法也可以用在函數(shù)的行參上面骨望。
function show(...arr1){ //直接來復(fù)制arguments這個偽數(shù)組硬爆,讓它變成真正的數(shù)組,從而擁有數(shù)組的方法擎鸠。
alert(arr1); //1234
arr1.push(5);
alert(arr1); //12345
}
show(1,2,3,4)
或者是通過循環(huán)來復(fù)制:
var arr1=[1,2,3,4];
var arr2=[];
for(var i=0; i<arr1.length; i++){
arr2[i]=arr1[i];
}
arr1.push(5);
arr2.push(6);
alert(arr1); //12345
alert(arr2); //12346
//或者是json
var json1={"name":"鵬哥","age":24,"job":"前端開發(fā)"};
var json2={};
for(var name in json1){
json2[name]=json1[name];
}
alert(JSON.stringify(json1)); //{"name":"鵬哥","age":24,"job":"前端開發(fā)"}
alert(JSON.stringify(json2)); //{"name":"鵬哥","age":24,"job":"前端開發(fā)"}
json1.a=1;
json2.b=2;
alert(JSON.stringify(json1)); //{"name":"鵬哥","age":24,"job":"前端開發(fā)","a":1}
alert(JSON.stringify(json2)); //{"name":"鵬哥","age":24,"job":"前端開發(fā)","b":2}
深復(fù)制和淺復(fù)制最根本的區(qū)別在于是否是真正獲取了一個對象的復(fù)制實體缀磕,而不是引用,
1)深復(fù)制在計算機中開辟了一塊內(nèi)存地址用于存放復(fù)制的對象劣光,
2)而淺復(fù)制僅僅是指向被復(fù)制的內(nèi)存地址袜蚕,如果原地址中對象被改變了,那么淺復(fù)制出來的對象也會相應(yīng)改變赎线。
所謂的淺復(fù)制廷没,只是拷貝了基本類型的數(shù)據(jù),而引用類型數(shù)據(jù)垂寥,復(fù)制后也是會發(fā)生引用颠黎,我們把這種拷貝叫做“(淺復(fù)制)淺拷貝”。
看例子:
var json1 = {"a":"李鵬","arr1":[1,2,3]}
function copy(obj1) {
var obj2 = {};
for (var i in obj1) {
obj2[i] = obj1[i];
}
return obj2;
}
var json2 = copy(json1);
json1.arr1.push(4);
alert(json1.arr1); //1234
alert(json2.arr1) //1234
而深復(fù)制的話滞项,我們要求復(fù)制一個復(fù)雜的對象狭归,那么我們就可以利用遞歸的思想來做,及省性能文判,又不會發(fā)生引用过椎。
看例子:
var json1={"name":"鵬哥","age":18,"arr1":[1,2,3,4,5],"string":'afasfsafa',"arr2":[1,2,3,4,5],"arr3":[{"name1":"李鵬"},{"job":"前端開發(fā)"}]};
var json2={};
function copy(obj1,obj2){
var obj2=obj2||{}; //最初的時候給它一個初始值=它自己或者是一個json
for(var name in obj1){
if(typeof obj1[name] === "object"){ //先判斷一下obj[name]是不是一個對象
obj2[name]= (obj1[name].constructor===Array)?[]:{}; //我們讓要復(fù)制的對象的name項=數(shù)組或者是json
copy(obj1[name],obj2[name]); //然后來無限調(diào)用函數(shù)自己 遞歸思想
}else{
obj2[name]=obj1[name]; //如果不是對象,直接等于即可戏仓,不會發(fā)生引用疚宇。
}
}
return obj2; //然后在把復(fù)制好的對象給return出去
}
json2=copy(json1,json2)
json1.arr1.push(6);
alert(json1.arr1); //123456
alert(json2.arr1); //12345
以上,結(jié)束赏殃。