javaScript中,对深拷贝和浅拷贝的理解

JavaScript中的深拷贝和浅拷贝是前端面试过程中频繁被问到的一个问题,今天我就给大家简单讲解一下!

一、简单介绍

JavaScript中的变量一共有两种类型的值:基本类型值和引用类型值。

  • 基本类型值

基本类型值,一般指String、Number、undefined、Null、Boolean等,他们在内存中都是存储在栈中的,直接访问该变量就可以得到存储在栈中的该变量的值。

若将一个变量的值赋值给另一个变量,则这两个变量在内存中都是独立的,修改其中一个变量的值,不会影响另一个变量。

下面我们来看一下图片介绍:

1.我们创建了第一个变量a,并赋值一个‘哈哈’这个值给它,则变量a在内存中的表现形式为:

2.然后我们又创建了一个变量b,接着把变量a的值赋值给变量b,则此时这两个变量在内存中的表现形式为:

可以看到在内存中的栈中,变量b独立占有了一个位置,并且还拥有了自己的值,为:‘哈哈’。

3.接着此时,我们把变量a的值改为‘嘿嘿’,那么此时这两个变量在内存中的栈中的情况是:

可以看到,只有变量a的值变为了‘嘿嘿’,这是因为变量b已经独立存在于内存中的栈中了,它不会受到变量a的影响。

  • 引用类型值

引用类型值,一般指Object、Array、Function等,他们在内存中是存在于栈与堆中的,我们要访问到引用类型值的话,首先需要先访问到变量在栈中的堆地址(指向堆中的值),然后再通过栈中的堆地址访问到存放在堆中的数据。

1.我们先创建一个变量a,并赋值一个‘{name:‘张三’}’,此时在内存中的情况就是:


我们可以看到,给变量a赋值了一个Object数据类型后,在内存中是,Object存储在内存中的堆中,而内存中的栈中存储的是变量名和对应堆中的Object的地址。

2.然后我们再创建一个变量b,接着将变量a赋值给变量b,此时内存中的情况是:

我们可以看到,当变量a把值赋值给了变量b的时候,只是在内存中的栈中创建了一个变量b,然后将变量a存储在栈中的堆地址1给了变量b,所以此时变量a和变量b都指向堆中的同一个值。

3.最后我们改变一下变量a中的值,a.name = '李四',此时内存中的情况是:

我们可以看出,因为变量a和变量b都指向堆中的同一个值,所以当通过变量a改变值时,变量a和变量b对应的值也都会跟着改变。

那么如何使变量b独立存在而不受变量a的影响呢?接下来我们看看浅拷贝和深拷贝。

二、浅拷贝

首先说一下,浅拷贝和深拷贝主要是针对像Objec和Array这两种比较复杂的对象的。

那么什么是浅拷贝呢?简单来说,就是一个变量赋值给另一个变量,其中一个变量的值改变,两个变量的值都跟着改变,这就叫做浅拷贝。

下面我们看一个简单的浅拷贝例子:

      let a = {
        name: '张三',
        age: 19,
        like: ['打篮球', '唱歌', '跳舞']
      };
      let b = {};
      for (let i in a) {
        b[i] = a[i];
      };
      a.name = '李四';
      a.like[0] = '睡觉';
      console.log('a:', a); //{name:'李四',age:19,like:['睡觉','唱歌','跳舞']}
      console.log('b:', b); //{name:'张三',age:19,like:['睡觉','唱歌','跳舞']}

我们可以看到,变量b通过一个一个获取变量a中的元素,已经独立存在,改变了变量a中的name,而变量b中的name却没有跟着改变。

但是,又能发现变量a改变了like值,变量b也随之改变了,好像并没有独立存在。

其实这是因为变量b在获取变量a的每一个元素时遇到了like,发现它是我们上边说到的引用类型,所以变量b就获得了一个地址,指向了堆中的值,所以变量b中的like仍然不是独立存在的。

这就是一个浅拷贝的例子,总结来说就是,浅拷贝只是将外层的值独立了出来,例如这个例子中的name、age,都不会随着变量a的改变而改变了;

但是由于对象结构复杂,内部的引用类型值没有独立出来,例如这个例子中的like,变量b获取到以后只是获取到了一个地址,它跟变量a的like指向同一个对象,所以变量b的like仍然会随着变量a的like改变而改变。

Object.assign

ES6语法中也给我们提供了一个浅拷贝的方法:Object.assign(target,sources)

  • target:拷贝的目标
  • sources:被拷贝的对象
      let a = {
        name: '张三',
        age: 19,
        like: ['打篮球', '唱歌', '跳舞']
      };
      let b = {};
      Object.assign(b,a);
      a.name = '李四';
      a.like[0] = '睡觉';
      console.log('a:',a);//{name:'李四',age:19,like:['睡觉','唱歌','跳舞']}
      console.log('b:',b);//{name:'张三',age:19,like:['睡觉','唱歌','跳舞']}

 

展开运算符...

      let a = {
        name: '张三',
        age: 19,
        like: ['打篮球', '唱歌', '跳舞']
      };
      let b = {...a};
      a.name = '李四';
      a.like[0] = '睡觉';
      console.log('a:', a); //{name:'李四',age:19,like:['睡觉','唱歌','跳舞']}
      console.log('b:', b); //{name:'张三',age:19,like:['睡觉','唱歌','跳舞']}

 

三、深拷贝

那么浅拷贝,是拷贝后,新拷贝的对象内部仍然有一部分数据会随着源对象的变化而变化;

那么深拷贝就是,拷贝后,新拷贝的对象内部所有数据都是独立存在的,不会随着源对象的改变而改变。

深拷贝的话,一共有两种方式:递归拷贝利用JSON函数深拷贝

  • 递归拷贝

实现原理:对变量中的每个元素进行获取,若遇到基本类型值,直接获取;若遇到引用类型值,则继续对该值的内部每个元素进行获取。

这里就不多做演示了,因为用递归来实现深拷贝很少,简单运用的话,用的最多的就是第二种深拷贝方式了。

但是还是会写个简单的递归拷贝例子进行参考。

let a = {
        name: '张三',
        age: 19,
        like: ['打篮球', '唱歌', '跳舞']
      };
      let b = {};
      function deepCopy(Aobj, Bobj) {
        //遍历旧的对象(被拷贝的对象)
        for (let i in Aobj) {
          if (Aobj[i] instanceof Array) { //判断i的值是不是为数组,其实数组也是Object类型
            Bobj[i] = [];
            deepCopy(Aobj[i], Bobj[i]);
          } else if (Aobj[i] instanceof Object) { //判断是不是对象
            Bobj[i] = {};
            deepCopy(Aobj[i], Bobj[i]);
          } else { //若是基本类型,直接赋值
            Bobj[i] = Aobj[i];
          }
        }
      };
      deepCopy(a, b);
      a.name = '李四';
      a.like[0] = '睡觉';
      console.log('a:', a); //{name:'李四',age:19,like:['睡觉','唱歌','跳舞']}
      console.log('b:', b); //{name:'张三',age:19,like:['打篮球','唱歌','跳舞']}

 

  • 利用JSON函数深拷贝

实现原理:将变量的值转变成字符串形式,然后再转化成对象赋值给新的变量。

      let a = {
        name: '张三',
        age: 19,
        like: ['打篮球', '唱歌', '跳舞']
      };
      let b = JSON.parse(JSON.stringify(a));
      a.name = '李四';
      a.like[0] = '睡觉';
      console.log('a:',a);//{name:'李四',age:19,like:['睡觉','唱歌','跳舞']}
      console.log('b:',b);//{name:'张三',age:19,like:['打篮球','唱歌','跳舞']}

可以看到,变量b已经完全独立存在了,无论变量a怎么变,变量b都保持不变了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

前端报刊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值