## 淺拷貝
### 1、數(shù)組和對(duì)象的的淺拷貝:

? ? let arr1 = [1,2,3,4,5];
? ? let arr2 = arr1;
? ? arr2[0] = 5
? ? console.log(arr1);
? ? console.log(arr2);
如上圖可知,當(dāng)我們改變arr2數(shù)組里的元素的時(shí)候,arr1頁是會(huì)跟著一起變化,這就讓咱們一時(shí)間無法理解到底怎么回事了,這時(shí)候我們可以借助之前學(xué)過的只是進(jìn)行理解!\
我們學(xué)過基本數(shù)據(jù)類型和**引用數(shù)據(jù)類型**,這里的arr1和arr2是共用一個(gè)對(duì)象地址,這個(gè)對(duì)象地址,arr1只是把對(duì)象地址復(fù)制給了arr2,而不是再堆棧中新建了一個(gè)儲(chǔ)存空間!堆棧的知識(shí)我們就不在這個(gè)章節(jié)做過多介紹,后續(xù)會(huì)單獨(dú)講解!
### 2、對(duì)象的方法Object.assign():

? ? let obj2 = Object.assign({}, obj);
? ? obj2.age = 20;
? ? obj2.child.name = 'feng';
? ? console.log(obj);
? ? console.log(obj2);
如上圖可以發(fā)現(xiàn),當(dāng)我們改變obj.age變?yōu)?0的時(shí)候,obj2是變化的,obj是沒有變化的,我們就以為是已經(jīng)實(shí)現(xiàn)了深拷貝。但是我們又改變了obj2對(duì)象里面的child對(duì)象中的name的時(shí)候,我們發(fā)現(xiàn)obj和obj2都變化了,這就說明內(nèi)部的child對(duì)象的引用地址還是同一個(gè),進(jìn)而證明此方法也是淺拷貝,并不會(huì)對(duì)深層次的對(duì)象進(jìn)行拷貝!
同理,像concat方法結(jié)果也是一樣的,都是淺拷貝!
### 3、可以用jes6的方法flat()實(shí)現(xiàn)淺拷貝:

? ? let arr = [1,2,[3,4,5,[6,7,8,9]]];
? ? let arr1 = arr.flat();
? ? arr1[0] = 0;
? ? arr1[2][0] = 10;
? ? console.log(arr);
? ? console.log(arr1);
這個(gè)es6的方法flat()原本是實(shí)現(xiàn)數(shù)組的扁平化所引入的一個(gè)方法,但是這個(gè)方法也可以巧妙的實(shí)現(xiàn)數(shù)組或?qū)ο蟮臏\拷貝,如上圖所示,和之前Object.assign()方法一樣,屬于淺拷貝!
## 深拷貝
### 1、遞歸調(diào)用實(shí)現(xiàn)深拷貝:

? ? function deepClone(obj) {
? ? ? ? let cloneObj = Array.isArray(obj) ? [] : {};
? ? ? ? // 也可以這么做,這種是我們沒有es6方法isArray時(shí)候常用的方法判斷一個(gè)對(duì)象是否是數(shù)組
? ? ? ? // let cloneObj = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {};
? ? ? ? for (const key in obj) {
? ? ? ? ? ? ? ? if (obj.hasOwnProperty(key)) {
? ? ? ? ? ? ? ? ? ? ? ? //判斷對(duì)象里面的元素是不是對(duì)象
? ? ? ? ? ? ? ? ? ? ? ? if (obj[key] && typeof obj[key] === 'object') {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cloneObj[key] = deepClone(obj[key]);
? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果不是對(duì)象,就直接放到對(duì)象cloneObj里
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cloneObj[key] = obj[key];
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return cloneObj;
? ? }
? ? let obj = [1,2,{name: 'peng'},5];
? ? obj1 = deepClone(obj);
? ? obj1[0] = 0;
? ? obj1[2].name = 'feng';
? ? console.log(obj);
? ? console.log(obj1);
如上圖所示,我們看到定義一個(gè)方法deepClone深拷貝,采用遞歸遍歷會(huì)去復(fù)制一個(gè)對(duì)象里的每一層數(shù)據(jù),保證復(fù)制出來的對(duì)象和之前的對(duì)象不是一個(gè)對(duì)象,不會(huì)共用一個(gè)引用地址!我們給復(fù)制出來的對(duì)象改變數(shù)組的第一個(gè)元素和數(shù)組里面對(duì)象的name屬性時(shí),都不會(huì)對(duì)原對(duì)象有影響,這樣我們就實(shí)現(xiàn)了傳統(tǒng)意義上的深拷貝!接下來我們?cè)倏纯催€有沒有其他方式可以實(shí)現(xiàn)深拷貝!
### 2、可以用對(duì)象的方法JSON.parse()和JSON.stringify()實(shí)現(xiàn)深拷貝:

? ? let obj = {
? ? ? ? a: {
? ? ? ? ? ? b: 'peng'
? ? ? ? }
? ? }
? ? let cloneObj = JSON.parse(JSON.stringify(obj));
? ? cloneObj.a.b = 'feng';
? ? console.log(obj)
? ? console.log(cloneObj);
如上圖所示,我們可以看到這個(gè)方法是可以改變對(duì)象深層次的數(shù)據(jù)的,所以這個(gè)方法是可以實(shí)現(xiàn)深拷貝的!
但是這個(gè)方法有弊端;
-? 屬性為undefined是不會(huì)被拷貝的,屬性拷貝不到
-? symbol類型的和上面undefined一樣拷貝不到
-? 如果屬性是個(gè)function,那么沒辦法拷貝
-? 不能解決循環(huán)引用的對(duì)象
所以我們盡可能還是不要用此方法,但是要了解!
### 3、可以用jQuery的方法extend()實(shí)現(xiàn)深拷貝:
$.extend([deep], target, object)
第一個(gè)參數(shù)為是否是深拷貝,true為深拷貝,反之;第二個(gè)參數(shù)為拷貝為對(duì)象還是數(shù)組,第三個(gè)參數(shù)為要拷貝的目標(biāo)值對(duì)象或者數(shù)組

? ? let obj = [0,1,[2,3],4],
? ? obj1 = $.extend(true,[],obj);
? ? obj[0] = 1;
? ? obj[2][0] = 1;
? ? console.log(obj);
? ? console.log(obj1);
如上圖我們發(fā)現(xiàn)無論是第一層數(shù)據(jù)還是第二層數(shù)據(jù),都是只有被修改的對(duì)象才會(huì)改變,另外一個(gè)復(fù)制出來的對(duì)象是不會(huì)改變的!實(shí)現(xiàn)了深拷貝!
## 總結(jié)
**實(shí)際上深淺拷貝的宗旨就是復(fù)制的對(duì)象是否是一個(gè)全新的對(duì)象,如果是共同引用通一個(gè)對(duì)象的引用地址,或者是只能改變一層的對(duì)象或數(shù)組的引用地址而不是整個(gè)數(shù)組或?qū)ο笏袑蛹?jí)都改變的話,這就是個(gè)淺拷貝,如果能復(fù)制出一個(gè)全新的對(duì)象,引用地址都是不一樣的,那么就是深拷貝!如果要是使用深拷貝那么久用deeoClone方法嚴(yán)謹(jǐn)!橋拷貝的話那幾個(gè)都差不多,可自行考慮。感謝大家的支持!**