js的深拷贝与浅拷贝!

## 浅拷贝

### 1、数组和对象的的浅拷贝:

![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);

如上图可知,当我们改变arr2数组里的元素的时候,arr1页是会跟着一起变化,这就让咱们一时间无法理解到底怎么回事了,这时候我们可以借助之前学过的只是进行理解!\

我们学过基本数据类型和**引用数据类型**,这里的arr1和arr2是共用一个对象地址,这个对象地址,arr1只是把对象地址复制给了arr2,而不是再堆栈中新建了一个储存空间!堆栈的知识我们就不在这个章节做过多介绍,后续会单独讲解!

### 2、对象的方法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);

如上图可以发现,当我们改变obj.age变为20的时候,obj2是变化的,obj是没有变化的,我们就以为是已经实现了深拷贝。但是我们又改变了obj2对象里面的child对象中的name的时候,我们发现obj和obj2都变化了,这就说明内部的child对象的引用地址还是同一个,进而证明此方法也是浅拷贝,并不会对深层次的对象进行拷贝!

同理,像concat方法结果也是一样的,都是浅拷贝!

### 3、可以用jes6的方法flat()实现浅拷贝:

![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);

这个es6的方法flat()原本是实现数组的扁平化所引入的一个方法,但是这个方法也可以巧妙的实现数组或对象的浅拷贝,如上图所示,和之前Object.assign()方法一样,属于浅拷贝!

## 深拷贝

### 1、递归调用实现深拷贝:

![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时候常用的方法判断一个对象是否是数组

        // let cloneObj = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {};

        for (const key in obj) {

                if (obj.hasOwnProperty(key)) {

                        //判断对象里面的元素是不是对象

                        if (obj[key] && typeof obj[key] === 'object') {

                                cloneObj[key] = deepClone(obj[key]);

                        } else {

                                // 如果不是对象,就直接放到对象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);

如上图所示,我们看到定义一个方法deepClone深拷贝,采用递归遍历会去复制一个对象里的每一层数据,保证复制出来的对象和之前的对象不是一个对象,不会共用一个引用地址!我们给复制出来的对象改变数组的第一个元素和数组里面对象的name属性时,都不会对原对象有影响,这样我们就实现了传统意义上的深拷贝!接下来我们再看看还有没有其他方式可以实现深拷贝!

### 2、可以用对象的方法JSON.parse()和JSON.stringify()实现深拷贝:


![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);


如上图所示,我们可以看到这个方法是可以改变对象深层次的数据的,所以这个方法是可以实现深拷贝的!

但是这个方法有弊端;

-  属性为undefined是不会被拷贝的,属性拷贝不到

-  symbol类型的和上面undefined一样拷贝不到

-  如果属性是个function,那么没办法拷贝

-  不能解决循环引用的对象

所以我们尽可能还是不要用此方法,但是要了解!

### 3、可以用jQuery的方法extend()实现深拷贝:

$.extend([deep], target, object)

第一个参数为是否是深拷贝,true为深拷贝,反之;第二个参数为拷贝为对象还是数组,第三个参数为要拷贝的目标值对象或者数组

![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);


如上图我们发现无论是第一层数据还是第二层数据,都是只有被修改的对象才会改变,另外一个复制出来的对象是不会改变的!实现了深拷贝!

## 总结

**实际上深浅拷贝的宗旨就是复制的对象是否是一个全新的对象,如果是共同引用通一个对象的引用地址,或者是只能改变一层的对象或数组的引用地址而不是整个数组或对象所有层级都改变的话,这就是个浅拷贝,如果能复制出一个全新的对象,引用地址都是不一样的,那么就是深拷贝!如果要是使用深拷贝那么久用deeoClone方法严谨!桥拷贝的话那几个都差不多,可自行考虑。感谢大家的支持!**

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容