慎用JS中的slice()、cancat()和assign()方法來複制數組

1、原數組裏的數據不包含引用類型

let arr1 = [1 , 2 , 3 , "hello" , "world"];  //原數組

一、使用 slice() 方法

拷貝數組:數組

let arr2 = arr1.slice(0);
console.log(arr2);   //打印新數組
[1 , 2 , 3 , "hello" , "world"];  //新數組

修改通過 slice() 拷貝過的新數組:code

arr2[3] = "Hello";
console.log(arr1);  //打印舊數組
[1 , 2 , 3 , "hello" , "world"]   
console.log(arr2);   //打印新數組
[1 , 2 , 3 , "Hello" , "world"]

<font color="red">結論:使用 slice() 方法拷貝數組,而後修改新數組,不會影響到舊數組的值。</font>對象

二、使用 concat() 方法

拷貝數組:遞歸

let arr3 = [].conat(arr1);
console.log(arr3);   //打印新數組
[1 , 2 , 3 , "hello" , "world"];  //新數組

修改通過 concat() 拷貝過的新數組內存

arr3[3] = "Hello";
console.log(arr1);  //打印舊數組
[1 , 2 , 3 , "hello" , "world"]   
console.log(arr3);   //打印新數組
[1 , 2 , 3 , "Hello" , "world"]

<font color="red">結論:使用 concat() 方法拷貝數組,而後修改新數組,不會影響到舊數組的值。</font>string

三、使用簡單的數組賦值語法

拷貝數組:io

let arr4 = arr1;
console.log(arr4);   //打印新數組
[1 , 2 , 3 , "hello" , "world"];  //新數組

修改通過簡單賦值過的新數組console

arr4[3] = "Hello";
console.log(arr1);  //打印舊數組
[1 , 2 , 3 , "Hello" , "world"]   
console.log(arr4);   //打印新數組
[1 , 2 , 3 , "Hello" , "world"]

<font color="red">結論:使用數組簡單賦值方法拷貝數組,而後修改新數組,會影響到舊數組的值。</font>function

<font color="red">緣由:這種簡單賦值的方法屬於數組的淺拷貝,數組arr1和數組arr4共用同一塊內存,其中一個數組改變,另外一個數組也會跟着改變。</font>object

2、原數組裏的數據包含引用類型

let arr1 = [1 , 2 , 3 , {"name" : "張小二"} , {"sex" : "male"}];  //原數組

一、使用 slice() 方法

拷貝數組:

let arr2 = arr1.slice(0);
console.log(arr2);   //打印新數組
[1 , 2 , 3 , {"name" : "張小二"} , {"sex" : "male"}];  //新數組

修改通過 slice() 拷貝過的新數組:

arr2[3].name = "隔壁張小二";
console.log(arr1);  //打印舊數組
[1 , 2 , 3 , {"name" : "隔壁張小二"} , {"sex" : "male"}]   
console.log(arr2);   //打印新數組
[1 , 2 , 3 , {"name" : "隔壁張小二"} , {"sex" : "male"}]

<font color="red">
結論:使用 slice() 方法拷貝數組,而後修改新數組,會改變舊數組的值。
</font>

二、使用 concat() 方法

拷貝數組:

let arr3 = [].conat(arr1);
console.log(arr3);   //打印新數組
[1 , 2 , 3 , {"name" : "張小二"} , {"sex" : "male"}];  //新數組

修改通過 concat() 拷貝過的新數組

arr3[3].name = "隔壁張小二";
console.log(arr1);  //打印舊數組
[1 , 2 , 3 , {"name" : "隔壁張小二"} , {"sex" : "male"}]   
console.log(arr3);   //打印新數組
[1 , 2 , 3 , {"name" : "隔壁張小二"} , {"sex" : "male"}]

<font color="red">
結論:使用 concat() 方法拷貝數組,而後修改新數組,會改變舊數組的值。
</font>

3、緣由分析

一、數組的淺拷貝

(1)數組的直接賦值屬於數組的淺拷貝,JS存儲對象都是存內存地址的,因此淺拷貝會致使新數組和舊數組共用同一塊內存地址,其中一個數組變化,另外一個數組也會相應的變化。

(2)數組內部不含有引用類型,使用slice() 、concat() 和 assign() 方法都屬於數組的深拷貝,一個數組變化,另外一個數組不受影響。

(3)數組內部含有引用類型,使用slice() 、concat() 和 assign() 方法,非引用類型的值屬於深拷貝,引入類型的值屬於淺拷貝,一個數組變化,另外一個也會相應的變化。

4、解決辦法(含有引入類型的數組)

方法一:遞歸

let cloneObj = function(obj){
    let str, newobj = obj.constructor === Array ? [] : {};
    if(typeof obj !== 'object'){
        return;
    } else if(window.JSON){
        str = JSON.stringify(obj), //系列化對象
        newobj = JSON.parse(str); //還原
    } else {
        for(var i in obj){
            newobj[i] = typeof obj[i] === 'object' ? 
            cloneObj(obj[i]) : obj[i]; 
        }
    }
    return newobj;
};

let newArr = cloneObj(oldArr);

方法二:經過JSON解析解決

let newArr = JSON.parse(JSON.stringify(oldArr));
相關文章
相關標籤/搜索