JS中的深拷贝与浅拷贝

165 阅读2分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

我们做开发时,会发现复制一个对象时,当改变对象新的对象时,原来的对象也发生了变化,其实因为对象是按引用传递,它们都是保存在一个内存的同个位置,改变对象时,也改变了引用的地址。但我们往往需要拷贝的是一个新的对象,改变值同时也不改变原来的,这时就需要用到深度拷贝和浅度拷贝了。

浅度拷贝:复制一层对象的属性,并不包括对象里面的为引用类型的数据,当改变拷贝的对象里面的引用类型时,源对象也会改变。

深度拷贝:重新开辟一个内存空间,需要递归拷贝对象里的引用,直到子属性都为基本类型。两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

使用方法

浅拷贝:

  1. Object.assign方法
Object.assign(target, ...sources)

对于只有一层的对象,就是说对象所有的属性值都是基本数据类型,不包含引用数据类型,使用Object.assign进行浅拷贝就可以了。

  1. Array.prototype.slice()
arr.slice(begin, end);

Array.prototype.slice将arguments类数组转为真正的数组,它返回一个浅拷贝后的的新数组

  1. 扩展运算符
let cloneObj = { ...obj };

扩展运算符Object.assign()有同样的缺陷,对于值是对象的属性无法完全拷贝成2个不同对象,但是如果属性都是基本类型的值的话,使用扩展运算符更加方便

深拷贝:

1.遍历递归

var obj1 = {
    a:{
        b:1
    }
};
function deepClone(obj) {
    var cloneObj = {}; //在堆内存中新建一个对象
    for(var key in obj){ //遍历参数的键
       if(typeof obj[key] ==='object'){ 
          cloneObj[key] = deepClone(obj[key]) //值是对象就再次调用函数
       }else{
           cloneObj[key] = obj[key] //基本类型直接复制值
       }
    }
    return cloneObj 
}
var obj2 = deepClone(obj1);
obj1.a.b = 2;
console.log(obj2); //{a:{b:1}}

遍历递归就是一种深拷贝的方法,就是说不管对象有多少层级,都对他进行遍历,把他每一层级的属性都重新复制给新对象的属性,这样产生的新对象就不会再受原对象的影响。

2.JSON.stringify和JSON.parse

利用JSON.stringify和JSON.parse也可以实现对象的深拷贝

let obj1 = { a:1, b:[1,2,3] } 

let str = JSON.stringify(obj1) 

let obj2 = JSON.parse(str)

但是要注意,这种方法只适合对象的属性当中没有function或 RegExp 这些值,因为字符串没法对这种类型进行解析