彻底搞懂什么是深拷贝和浅拷贝

本文深入探讨了JavaScript中深拷贝和浅拷贝的概念及其实现方式,通过具体实例讲解了两者之间的区别,并提供了实现深拷贝的递归函数和JSON方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

更详细的文章请转看: 浅谈Javacript浅拷贝和深拷贝的实现

深拷贝和浅拷贝,主要是对象发生复制的时候,根据复制的层级不同来区分的。很多人在这里经常变量赋值发生混淆。我们前面知道了,对于JavaScript数组等复杂的数据类型来说,将其赋值给其它变量,其实只是复制了对象的地址给它,两个变量指向的是同一个对象,因此普通的赋值既不是深拷贝也不是浅拷贝

浅拷贝

所谓浅拷贝就是指对象复制的时候只复制一层。

var xiaoHong = {
    name: '小红',
    age: 18
}

var zhangSan = {
    name: '张三',
    age: 20,
    girl: xiaoHong
}

上面的代码在内存中我们可以这样描述:

在这里插入图片描述

也就是说,对象里面的值还是个对象(引用类型),如果我们去复制zhangSan这个对象,我们可以这样复制:

var xiaoMing = {};
// 将zhangSan的所有属性都复制给xiaoMing
for (var i in zhangSan){
    // 检查对象是否有用某个属性
    if (zhangSan.hasOwnProperty(i)) {
    	xiaoMing[i] = zhangSan[i];
    }
}
console.log(xiaoMing);

我们在继续运行代码:

xiaoMing.girl.name = '花花';
// 我们发现,这两个对象的girl属性指向的是同一个对象
console.log(xiaoMing);
console.log(zhangSan);

我们发现,这两个对象的girl属性指向的事同一个对象,一个发生变化的时候,另一个跟着也会变。这种只复制对象一层的情况,我们称之为浅拷贝,内存中的样子是这样的:

在这里插入图片描述

// 浅拷贝封装的函数
// 对象的拷贝的目的是得到一个新对象
function simpleCopy(obj) {
    var newObj = {};
    for (var key in obj) {
        // 检查对象是否有用某个属性
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}
深拷贝

深拷贝是指复制对象的所有层级。就像前面的例子一样,深拷贝完成后应该是这样的效果:

在这里插入图片描述

也就是说,所有层级都是复制出来了,而且互不干涉,就像克隆的一样,长得一模一样,但是所有内容都是相互独立。

怎么实现深拷贝的效果呢?常用的方法有两种:

  1. 转成JSON字符串,再转成对象。

    var xiaoHong = {
        name: '小红',
        age: 18
    }
    
    var zhangSan = {
        name: '张三',
        age: 20,
        girl: xiaoHong
    }
    
    var xiaoMing = JSON.parse(JSON.stringify(zhangSan));
    
    xiaoMing.girl.name = '小花';
    console.log(xiaoMing);
    console.log(zhangSan);
    
  2. 使用递归处理

    我们上面的例子写的比较简单,只有两层,因此深拷贝也只需要拷贝两层,其实我们很多时候是不知道一个对象有多少层级的,因此递归比较适合。

    var xiaoHong = {
        name: '小红',
        age: 18
    }
    
    var zhangSan = {
        name: '张三',
        age: 20,
        girl: xiaoHong
    }
    
    var xiaoMing = deepCopy(zhangSan);
    xiaoMing.girl.name = '小花';
    console.log(xiaoMing);
    console.log(zhangSan);
    

实现深拷贝:

 // 方法一:
  function deepClone(obj) {
    var result = Array.isArray(obj) ? [] : {};
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (typeof obj[key] === 'object' && obj[key]!==null) {
          result[key] = deepClone(obj[key]); 
        } else {
          result[key] = obj[key];
        }
      }
    }
    return result;
  }
  
方法二:
	function deepClone(arr){
    	return JSON.parse(JSON.stringify(arr))
	}
递归函数

所谓递归函数就是指调用自己的函数。

// 求两个整数之间的所有整数的和
function sum(start, end) {
    var total = start;

    if (start < end) {
        start++;
        // 自己调用自己了
        total = total + sum(start, end);
    } 
    return total;
}
console.log(sum(1, 5));

/**
 * total 的值的变化
 * start = 1 时
 * total = 1 + sum(2,5) 在内存中等着
 * start = 2 时
 * total = 2 + sum(3,5) 在内存中等着
 * start = 3 时
 * total = 3 + sum(4,5) 在内存中等着
 * start = 4 时
 * total = 4 + sum(5,5) 在内存中等着
 * start = 5 时,发现不符合继续调用条件,if执行完,继续执行下面的代码
 * 由于if之前发生了一次total的赋值,此时return的total的值为5;即sum(5,5)的之是5
 * 然后在内存中等着的total = 4 + sum(5,5) 的值就是 4 + 5 = 9,执行完后继续执行到return total,
 * 返回值是 9,即:sum(4,5) 返回9
 * 然后在内存中等着的total = 3 + sum(4,5) 的值就是 3 + 9 = 12,执行完后继续执行到return total,
 * 返回值是 12,即:sum(3,5) 返回12
 * 然后在内存中等着的total = 2 + sum(3,5) 的值就是 2 + 12 = 14,执行完后继续执行到return total,
 * 返回值是 14,即:sum(2,5) 返回14
 * 然后在内存中等着的total = 1 + sum(2,5) 的值就是 1 + 14 = 15
 * 此时相当于第一轮的if语句执行完,继续执行到return total,最终返回值为15
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值