一、數組淺拷貝
在使用JavaScript對數組進行操作的時候,我們經常需要將數組進行備份.
如下代碼,如果只是簡單才用賦值的方法,那么我們只要更改其中的任何一個,然后其他的也會跟着改變,這就導致了問題的發生
var arr1 = ["red","yellow","black"]; var arr2 = arr1; arr2[1] = "green"; console.log("數組的原始值:" + arr1 ); console.log("數組的新值:" + arr2);
測試結果如下
像上面的這種直接賦值的方式就是數組的淺拷貝,淺拷貝改變其中一個數組,另外一個數組也會跟着改變。很多時候,這不是我們想要的。
二、數組深拷貝方法
(1)js的slice方法
對於array對象的slice函數,返回一個數組的一段。(仍為數組) arrayObj.slice(start, [end])
參數: arrayObj 必選項。一個 Array 對象。 start 必選項。arrayObj 中所指定的部分的開始元素是從零開始計算的下標。 end可選項。arrayObj 中所指定的部分的結束元素是從零開始計算的下標。
說明: slice 方法返回一個 Array 對象,其中包含了 arrayObj 的指定部分。 slice 方法一直復制到 end 所指定的元素,但是不包括該元素。 如果 start 為負,將它作為 length + start處理,此處 length 為數組的長度。 如果 end 為負,就將它作為 length + end 處理,此處 length 為數組的長度。 如果省略 end ,那么 slice 方法將一直復制到 arrayObj 的結尾。 如果 end 出現在 start 之前,不復制任何元素到新數組中。
測試例子:
var arr1 = ["1","2","3"]; var arr2 = arr1.slice(0); arr2[1] = "9"; console.log("數組的原始值:" + arr1 ); console.log("數組的新值:" + arr2 );
測試結果:
如測試結果顯示,通過JS的slice方法,改變拷貝出來的數組的某項值后,對原來數組沒有任何影響。
(2)js的concat方法
concat() 方法用於連接兩個或多個數組。該方法不會改變現有的數組,而僅僅會返回被連接數組的一個副本。
語法:arrayObject.concat(arrayX,arrayX,......,arrayX)
說明:返回一個新的數組。該數組是通過把所有 arrayX 參數添加到 arrayObject 中生成的。如果要進行 concat() 操作的參數是數組,那么添加的是數組中的元素,而不是數組。
測試例子:
var arr1 = ["1","2","3"]; var arr2 = arr1.concat(); arr2[1] = "9"; console.log("數組的原始值:" + arr1 ); console.log("數組的新值:" + arr2 );
測試結果:
如測試結果顯示,通過JS的concat方法,改變拷貝出來的數組的某項值后,對原來數組沒有任何影響。
(3)js遍歷數組的方法
測試例子:
var arr1 = [1,2,3];//原來數組
var arr2 = [];//新數組
function deepCopy(arry1, arry2){
var length = arry1.length;
for(var i = 0;i<length;i++){
arry2[i] = arry1[i];
}
}
deepCopy(arr1, arr2);
arr2[0] =5;
console.log(arr1);
console.log(arr2);
測試結果:
三、slice,concat方法的局限性
測試例子1
var arr1 = [{"name":"weifeng"},{"name":"boy"}];//原數組 var arr2 = [].concat(arr1);//拷貝數組 arr1[1].name="girl"; console.log(arr1);// [{"name":"weifeng"},{"name":"girl"}] console.log(arr2);//[{"name":"weifeng"},{"name":"girl"}]
測試結果:
測試例子2
var a1=[["1","2","3"],"2","3"],a2; a2=a1.slice(0); a1[0][0]=0; //改變a1第一個元素中的第一個元素 console.log(a2[0][0]); //影響到了a2 var b1=[["1","2","3"],"2","3"],b2; b2=b1.slice(0); b1[0][0]=0; //改變a1第一個元素中的第一個元素 console.log(b2[0][0]); //影響到了a2
測試結果:
從上面兩個例子可以看出,由於數組內部屬性值為引用對象,因此使用slice和concat對對象數組的拷貝,整個拷貝還是淺拷貝,拷貝之后數組各個值的指針還是指向相同的存儲地址。
因此,slice和concat這兩個方法,僅適用於對不包含引用對象的一維數組的深拷貝