JS 深拷贝与浅拷贝

哈希珊瑚
• 阅读 1426

其实在工作写代码和面试中,会经常碰到这两个概念:深拷贝,浅拷贝。但今天的重点是深拷贝。

下面我将简单介绍下什么是深拷贝,浅拷贝?

浅拷贝就是直接将一个Object对象所有的属性和属性值复制给另一个Object对象。这样导致的后果是,新对象和老对象相同的Object类型的属性值在内存中的指向是一样的,也就是新对象和老对象的Object类型的同一属性值指向的是同一块内存。因此修改新对象或者原对象,都会互相干扰。

深拷贝是将一个Object对象的内容完全拷贝一份给新对象。修改原对象的属性或者属性值,都不会影响新对象。原对象和新对象是完全独立的,互不影响。

然后补充一点,直接赋值

直接赋值,如果针对的是基本类型,那么就是简单的赋值。如果针对的是Object类型,那就是将原Object对象的地址赋值给新对象,也就是说,原对象与新对象其实是一模一样的,一旦对(任何)属性或者(任何)属性值做修改,原对象和新对象都会互相影响。

今天的重点是深拷贝,浅拷贝没啥可讲的。
talk is cheap,show me the code!

上浅拷贝代码:

function shallowCopy(obj) {
    if (!(obj instanceof Object)) {
        return obj;
    }
    let newObj = {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

下面重点说说深拷贝

第一个方案是使用JSON.stringify将Object转化为Json字符串,然后在用JSON.parse将json字符串转为Object对象。我们来测试下:

let obj1 = {
    "name": "Umbrella", "sex": "man",
    "brothers": {
        "Umbrella001": 22, "Umbrella002": 23
    }
};
let obj2 = obj1;                    //直接赋值
let obj22 = shallowCopy(obj1);      //浅拷贝
obj2.name = "Umbrella1024";
console.log(obj1);
console.log(obj22);

let obj3 = JSON.parse(JSON.stringify(obj1));
console.log(obj3);
obj1.sex = "boy";
console.log(obj3);

obj1.brothers['Umbrella001'] = 99;
console.log(obj22);

下面是运行截图

JS 深拷贝与浅拷贝

我们可以看到:
1.直接赋值后,修改任何属性或者属性值,源对象和新对象会互相影响,改了obj2,obj1就随之改变了。
2.浅拷贝,修改了属性值为Object类型的,源对象和新对象才会互相影响。可以观察obj22和obj1的变化。
3.观察obj3和obj1,可以知道利用JSON.stringify、JSON.parse实现的深拷贝,是可以实现深拷贝的。

我们再给对象加多点属性,比如加个函数。

let obj4 = {
    "name": "Umbrella",
    "sex": "man",
    "introduce": function () {
        console.log("My name is " + this.name);
    }
};

obj4.introduce();

let obj5 = JSON.parse(JSON.stringify(obj4));
console.log(obj5);
obj5.introduce();

运行截图:

JS 深拷贝与浅拷贝

JS 深拷贝与浅拷贝

可以看到采用这种方法,只可以将对象的非Function属性拷贝出来。所以通过JSON.parse和JSON.stringify实现的深拷贝不完美。

那么我分享下我自己写的一个对象深拷贝的方法,这就是我个人比较常用的方案了。

function deepCopy(obj) {
    if (obj instanceof Object) {
        let newObj = {};
        if (Array.isArray(obj)) {
            let arr = [];
            obj.forEach(item => {
                arr.push(deepCopy(item));
            })
            return arr;
        } else {
            for (let key in obj) {
                let value = obj[key];
                if (typeof value == 'function') {
                    newObj[key] = value.bind(newObj);
                } else if (typeof value == 'object') {
                    if (Array.isArray(value)) {
                        newObj[key] = [];
                        value.forEach(item => {
                            newObj[key].push(deepCopy(item));
                        })
                    } else {
                        newObj[key] = deepCopy(value);
                    }
                } else {
                    newObj[key] = value;
                }
            }
        }
        return newObj;
    } else {
        return obj;
    }
}

可以看到,我写的这个方法中,对属性值为function的做了处理。

我们来对这个deepCopy做测试,看是否是满足需求,可用的。

let obj88 = {
    "name": "obj88",
    "sex": "man",
    "introduce": function () {
        console.log("My name is " + this.name);
    }
}

let obj8 = {
    "name": "Umbrella",
    "sex": "man",
    "introduce": function () {
        console.log("My name is " + this.name);
    },
    "brothers": [obj88]
};

console.log(obj8);

let obj9 = deepCopy(obj8);              //深拷贝
obj9.name = "Flex";

console.log(obj8);
console.log(obj9);

obj88.name = "obj88 Plus";
obj9.introduce();
obj9.brothers[0].introduce();

运行结果:

JS 深拷贝与浅拷贝

可以看到,我们的deepCopy函数是能够实现深拷贝的,并且也兼容了属性值类型为function的处理,也是可以拷贝的。

如有错漏,欢迎大佬们拍砖~

点赞
收藏
评论区
推荐文章
翼
4年前
ES6的解构赋值是深拷贝or浅拷贝?
面试时候有面试官问到ES6的解构赋值是深拷贝还是浅拷贝?,这里做一个总结.ES6的解构赋值,大家应该都清楚,就是可以快速取出数组或者对象中的值;我们先来看一个使用案例:更多的解构赋值知识可以查看:https://es6.ruanyifeng.com/docs/destructuring那么,ES6的解构赋值到底是深拷贝还是浅拷贝呢?我们先来看一下深拷贝和浅
Wesley13 Wesley13
3年前
java 复制Map对象(深拷贝与浅拷贝)
java复制Map对象(深拷贝与浅拷贝)CreationTime2018年6月4日10点00分Author:Marydon1.深拷贝与浅拷贝  浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象
Wesley13 Wesley13
3年前
java克隆之深拷贝与浅拷贝
版权声明:本文出自汪磊的博客,未经作者允许禁止转载。Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问的,所以理解深拷贝与浅拷贝是十分重要的。一、Java中创建对象的方式①:与构造方法有关
晴空闲云 晴空闲云
3年前
也谈JavaScript浅拷贝和深拷贝
网上关于这个话题,讨论有很多了,根据各路情况我自己整理了一下,最后还是能接近完美的实现深拷贝,欢迎大家讨论。javascript中的对象是引用类型,在复制对象的时候就要考虑是用浅拷贝还是用深拷贝。直接赋值对象是引用类型,如果直接赋值给另外一个对象,那么只是赋值一个引用,实际上两个变量指向的同一个数据对象,如果其中一个对象的属性变更,那么另外一个也会变更。示
Java对象拷贝原理剖析及最佳实践
作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的属性拷贝工具,包括Apache的
菜园前端 菜园前端
2年前
带你了解JS对象的浅拷贝和深拷贝
以下主要介绍了正常情况下的拷贝、浅拷贝、深拷贝三种方式的区别。正常拷贝:复制一个对象,它们的内存地址是相同的浅拷贝:拷贝对象的第一层属性深拷贝:拷贝对象多层的属性正常拷贝假设我们要复制一个对象,如果不对其进行深拷贝,那么改变其中一个对象后,另外一个对象也会
放学路上 放学路上
4年前
python 赋值引用 浅拷贝 深拷贝
一、基础概念1、直接赋值:其实就是对象的引用(别名)。2、浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。3、深拷贝(deepcopy):copy模块的deepcopy方法,完全拷贝了父对象及其子对象。二、代码示例importcopya1,2,3,4,'a','b'原始对象ba
Souleigh ✨ Souleigh ✨
4年前
实现深拷贝的多种方式
实现深拷贝的多种方式简单来说,深拷贝主要是将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为此时它自己在堆中开辟了自己的内存区域,不受外界干扰。浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。1.简单深拷贝(一层浅拷贝)①for循环拷贝//只复制第一层的浅拷贝javascriptfunc
Wesley13 Wesley13
3年前
Java深拷贝和浅拷贝
1.浅复制与深复制概念⑴浅拷贝(浅克隆)   复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。⑵深拷贝(深克隆)   复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深复制
Stella981 Stella981
3年前
JavaScript的深拷贝和浅拷贝
一、数据类型数据分为基本数据类型(String,Number,Boolean,Null,Undefined,Symbol)和对象数据类型。、1.基本数据类型的特点:直接存储在栈(stack)中的数据2.引用数据类型的特点:存储的是该对象在栈中引用,真实的数据放在堆内存里。引用数据类型在栈中存储了指针,该指针指向堆中该实
Stella981 Stella981
3年前
JavaScript基础心法——深拷贝和浅拷贝
!(https://oscimg.oschina.net/oscnet/c131215a5aaaeb7909d7398688df6ea6dcd.png)浅拷贝和深拷贝都是对于JS中的引用类型而言的,浅拷贝就只是复制对象的引用,如果拷贝后的对象发生变化,原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝。前言说到深浅拷贝,必须先
哈希珊瑚
哈希珊瑚
Lv1
残灯无焰影幢幢,此夕闻君谪九江。
文章
4
粉丝
0
获赞
0