js的深拷貝與淺拷貝!

## 淺拷貝

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

![kaobei1.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/192f4e00354e48768c7ce1db02b127a6~tplv-k3u1fbpfcp-watermark.image)

? ? 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():

![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/177b3fbe12384fd6804a20f832e73f13~tplv-k3u1fbpfcp-watermark.image)

? ? 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)淺拷貝:

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1a9b1f967db94304beea62aa0d1a02ac~tplv-k3u1fbpfcp-watermark.image)

? ? 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)深拷貝:

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0e7861e46cf446098d84fe959bb458e7~tplv-k3u1fbpfcp-watermark.image)

? ? 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)深拷貝:


![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a0d2083cd3bd42cc916638eb75194331~tplv-k3u1fbpfcp-watermark.image)

? ? 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ù)組

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ec4b885822314d0a8fc050bc8d3cc52e~tplv-k3u1fbpfcp-watermark.image)

? ? 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è)都差不多,可自行考慮。感謝大家的支持!**

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容