深拷貝和淺拷貝是針對複雜數據類型來講的,淺拷貝只拷貝一層,而深拷貝是層層拷貝。 這裏區分一下深拷貝和淺拷貝,淺拷貝經過直接賦值的方式(arr2=arr1)來實現arr2數組的建立,實質上只是將arr2指向了數組數據[1,2,3,4,5]在堆內存中的保存地址。也就是說arr一、arr2保存的是同一個堆內存地址。所以改變一個數組,會引發另外一個數組同步改變,由於本質上只有一個數組。 深拷貝則是在堆內存另外開闢一片地址,將數組數據[1,2,3,4,5]存放進去,而後將arr2指向這個新的地址。所以改變一個數組不會影響另外一個數組,兩個數組獨立變化。由於本質是兩個數組。數組
淺拷貝和深拷貝都是對於JS中的引用類型而言的,淺拷貝就只是複製對象的引用(堆和棧的關係,簡單類型Undefined,Null,Boolean,Number和String是存入堆,直接引用,object array 則是存入桟中,只用一個指針來引用值),若是拷貝後的對象發生變化,原對象也會發生變化。只有深拷貝纔是真正地對對象的拷貝。bash
淺拷貝的意思就是隻複製引用(指針),而未複製真正的值。ui
const originArray = [1,2,3,4,5];
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
console.log(cloneArray); // [1,2,3,4,5]
console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}
cloneArray.push(6);
cloneObj.a = {aa:'aa'};
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
複製代碼
上面的代碼是最簡單的利用 = 賦值操做符實現了一個淺拷貝,能夠很清楚的看到,隨着 cloneArray 和 cloneObj 改變,originArray 和 originObj 也隨着發生了變化。spa
就是對目標的徹底拷貝,不像淺拷貝那樣只是複製了一層引用,就連值也都複製了。 只要進行了深拷貝,它們老死不相往來,誰也不會影響誰。指針
目前實現深拷貝的方法很少,主要是兩種:code
利用 JSON 對象中的 parse 和 stringify,可是這種簡單粗暴的方法有其侷限性。當值爲undefined、function、symbol 會在轉換過程當中被忽略對象
ES6 中 引入了 Object.assgn 方法和 ... 展開運算符也能實現對對象的拷貝。遞歸
利用遞歸,遞歸的思想就很簡單了,就是對每一層的數據都實現一次 建立對象->對象賦值 的操做,簡單粗暴上代碼:內存
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判斷複製的目標是數組仍是對象
for(let keys in source){ // 遍歷目標
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){ // 若是值是對象,就遞歸一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 若是不是,就直接賦值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
複製代碼
let arr1 = [1,2,3,4,5];
let arr2 = [...arr1];
複製代碼
let arr1 = [1,2,3,4,5];
let arr2 = arr1.slice(0)
複製代碼
let arr1 = [1,2,3,4,5];
let arr2 = arr1.concat()
複製代碼