JS浅拷贝和深拷贝详解

1、为什么要用到拷贝?

在开发中我们经常需要复制一个对象。如果直接用赋值会有下面问题:

举个例子:

	// 创建一个对象
    const obj = {
      name: '张三',
      age: 18
    }
    // 直接赋值
    const obj1 = obj
    // 对obj1进行修改,obj也会被修改
    obj1.name = '李四'
    console.log(obj1);
    console.log(obj);

在这里插入图片描述

所以为了解决这个问题,我们就需要要用到拷贝

2、浅拷贝

首先浅拷贝和深拷贝只针对引用类型 ,
浅拷贝:拷贝的是地址

2.1 常见方法:

2.1.1 拷贝对象:

两种常见方法:

 Object.assgin() 或者 展开运算符 {...obj} 拷贝对象

Object.assgin( )实现浅拷贝对象

object.assign 将所有可枚举的属性,从一个或多个源对象复制到目标对象。

	const obj = {
      name: '张三',
      age: 18
    }
    const obj1 = {}
    //第一个参数写新对象,第二个参数写旧对象
    Object.assign(obj1,obj)
    console.log(obj1);
    obj1.name = '王五'
    console.log(obj1);
    console.log(obj);

在这里插入图片描述

{...obj}实现浅拷贝对象

扩展运算符可以实现对象的浅复制

 	const obj = {
      name: '张三',
      age: 18
    }
    const obj1 = {...obj} //展开运算符
    console.log(obj1);
    obj1.name = '云山'
    console.log(obj1);
    console.log(obj);

在这里插入图片描述

2.1.2 拷贝数组:

三种常见方法:

Array.prototype.concat()[...arr]
Array.prototype.slice()

Array.prototype.concat()实现浅拷贝数组

concat 方法用来合并数组,也可以用来实现浅拷贝。

	const arr = ['张三','李四','王五','赵六']
    const arr1 = []
    const arr2 = arr1.concat(arr)
    console.log(arr2);
    arr2[0] = '哈哈'
    console.log(arr2);
    console.log(arr);

在这里插入图片描述

[...arr]实现浅拷贝数组

	const arr = ['张三','李四','王五','赵六']
    const arr1 = [...arr]
    console.log(arr1);
    arr1[0] = '雪峰'
    console.log(arr1);
    console.log(arr);

在这里插入图片描述

Array.prototype.slice 实现浅拷贝数组

slice 方法用来复制数组,接受两个参数 startIndex 和 endIndex,
分别为复制开始的索引(包含当前索引的值)和复制结束的索引(不包含当前索引的值,包含结束索引前的值)。
如果不传 endIndex 参数,则从开始索引复制到数组末尾。

	const arr = ['张三','李四','王五','赵六']
    const arr1 = arr.slice()
    console.log(arr1);
    arr1[0] = '穆青'
    console.log(arr1);
    console.log(arr);

在这里插入图片描述
以上是一些浅拷贝的方法,浅拷贝拷贝的只有一层,多层会受影响。

举个例子理解理解一下什么是多层:

	const obj = {
      name: '张三',
      age: 18,
      family:{
        mother:"妈妈"
      }
    }
    const obj1 = {...obj}
    obj1.family.mother = '云云'
    console.log(obj1);
    console.log(obj);

在这里插入图片描述
在给obj1的mother更改为云云后,原对象obj里面的mother也发生了变化,显然这样是不合理的。所以我们就需要用到深拷贝。

3、 深拷贝

首先浅拷贝和深拷贝只针对引用类型
深拷贝:拷贝的是对象,不是地址

3.1常见方法:

3.1.1 通过递归实现深拷贝

我们先来了解一下什么是递归

函数递归: 如果一个函数在内部可以调用其本身,那么这个函数就是递归函数

1、简单理解: 函数内部自己调用自己, 这个函数就是递归函数

2、 递归函数的作用和循环效果类似

3、 由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return

举个例子理解一下:

 	let n = 1
    // fn就是递归函数
    function fn() {
      console.log('我要打印六次递归函数');
      if (n >= 6) {
        return
      }
      n++
      fn()//函数内部调用自己
    }
    fn()

在这里插入图片描述
了解完什么是递归之后我们就来写一个简版的深拷贝

  const obj = {
      name: '张三',
      age: 18,
      hobby:['健身','游泳'],
      family: {
        mother: '妈妈'
      }
    }
    const obj1 = {}
    function fn(newObj, oldObj) {
      for (let k in oldObj) {
        if (oldObj[k] instanceof Array) {// 判断是否为数组
          newObj[k] = []
          fn(newObj[k], oldObj[k])
        } else if (oldObj[k] instanceof Object) {// 判断是否为对象
          newObj[k] = {}
          fn(newObj[k], oldObj[k])
        } else {
          newObj[k] = oldObj[k]
        }
      }
    }
    fn(obj1, obj)
    console.log(obj);
    obj1.family.mother = '我'
    obj1.hobby[0] = '跑步'
    console.log(obj1);
    console.log(obj);

在这里插入图片描述

我们将新数组obj1的值进行了修改,通过递归的方式后,原对象是没有发生改变的。

注:进行判断的时候,一定要把数组写在对象前面,因为数组也是属于对象,不然判断是否为数组是执行不到的。

3.1.2 通过 lodash/cloneDeep(js库)实现

我们先从官网https://www.lodashjs.com/下载源文件到本地,然后引入到我们HTML文件里面。

我们来看看具体实现:

  <script src="./lodash.min.js"></script>
	const obj = {
      name : '张三',
      age : 18,
      hobby : ['健身','游泳'],
      family:{
        mother:'妈妈'
      }
    }
    const obj1 = _.cloneDeep(obj)
    console.log(obj);
    obj1.family.mother = '云韵'
    console.log(obj1);
    console.log(obj);

在这里插入图片描述

3.1.3 通过JSON.stringify()实现

实现思路:

先通过JSON.stringify()将obj对象转化为字符串,然后通过JSON.parse( ) 将字符串转化为对象,这样两个对象就互不干涉了。

示例:

 const obj = {
      name : '张三',
      age : 18,
      hobby : ['健身','游泳'],
      family:{
        mother:'妈妈'
      }
    }
   const obj2 = JSON.parse(JSON.stringify(obj))
   console.log(obj);
   obj2.family.mother = '美杜莎'
   console.log(obj2);
   console.log(obj);

在这里插入图片描述

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东方青云、

你的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值