1. 程式人生 > >JS--使用slice和concat對陣列的深拷貝和淺拷貝

JS--使用slice和concat對陣列的深拷貝和淺拷貝

一、陣列淺拷貝

在使用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這兩個方法,僅適用於對不包含引用物件的一維陣列的深拷貝