详解JS深拷贝与浅拷贝

167 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

本文将详解深拷贝与浅拷贝的实现方法和相应的优缺点

首先我们需要弄清楚两种数据类型:

基础类型:数值、字符串、布尔、null、undefined

var a = =100;
var b = a;
a = 50;
console.log(b);//100

基础类型,遇到 = 时,就是值的复制,存储地方在栈中

image.png

引用类型:统称为Object类型,细分有Object类型,Array类型,Date类型,Function类型等。

var obj1={
   a:1;
}
var obj2 = obj1;
obj2.a=2;
console.log(obj1.a)

对象类型,遇到 = 时,是内存地址的复制,所以改变obj2的值,obj1也会跟着改变

image.png

深拷贝与浅拷贝

浅拷贝:复制了地址,原来的变量和新建的变量指向了堆区的同一处地方,彼此会相互影响

深拷贝:在堆区中重新分配内存,原来的变量和新的变量指向不同的地址,虽然值现在相同,但是互不影响

浅拷贝的实现方法:

  1. 对象之间直接用等号赋值

    var obj1={
       a:1;
    }
    var obj2 = obj1;
    
  2. 以下方法可以处理一层的深拷贝,但是如果对象里又嵌套了对象,则内层的对象依旧只复制了地址(浅拷贝)

    • Object.assign()
    var hd = {
      name:"小周",
      age:19
    };
    var obj = Object.assign({},hd);
    
    • 展开表达式 语法:
新对象={...被拷贝的对象}
    var hd = {
      name:"小周",
      age:19
    };
    var obj = {...hd};
    
  • for循环进行浅拷贝
var hd ={
        name:"小周",
            age: 19,
    };
    var obj = {};
    for (const key in hd) {
        obj[key] = hd[key];
    }

深拷贝的实现方法:

  1. 自己一个字一个字的敲代码进行拷贝 优点:方便增删查改 缺点:很麻烦,得手动一个一个敲出来

  2. 将js对象先转化成json中的字符串,然后再转成js,就可以实现深拷贝

    var json = JSON.stringify(obj1);
    var js = JSON.parse(json);
    

    可也将两行代码合并成一行:

    var obj2 = JSON.parse(JSON.stringify(obj));
    

    优点:简单方便

    缺点:对象中的函数和正则表达式无法拷贝

  3. 递归

    function deepClone(newObj, obj) {
        //遍历obj的每一个成员,赋值给newObj
        for (var keys in obj) {
            if (obj[key] instanceof Array) {
                //数组,引用类型
                newObj[key] = [];
                deepClone(newObj[key], obj[key]);
            }
            else if (obj[key] instanceof Object) {
                //对象:引用类型
                newObj[key] = [];
                deepClone(newObj[key], obj[key]);
            }
            else {
                //值类型
                newObj[key] = obj[key];
            }
        }
    }
    

递归的思路: 因为引用类型有:数组,对象,所以我们在递归的时候需要判断一下,如果是引用类型的话,进一步递归深拷贝,如果只是值类型,则直接拷贝给新对象就行

  1. 遍历obj的每一个成员,赋值给newObj
  2. if来判断 obj 是否是array数据类型,如果是,就给newObj[key]new一个新的对象,然后递归深拷贝
  3. if来判断 obj 是否是对象数据类型,如果是,就给newObj[key]new一个新的对象,然后递归深拷贝 4.if判断如果是值类型,如果是,就直接拷贝。