前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝

面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝

作者头像
@零一
发布2021-01-29 16:19:33
4230
发布2021-01-29 16:19:33
举报
文章被收录于专栏:前端印象前端印象

浅显易懂的介绍Javascript中的深拷贝和浅拷贝

引言

先点赞,再看博客,顺手可以点个关注。 微信公众号搜索【Lpyexplore的编程小屋】,关注我,带你在python爬虫的过程中学习前端

JavaScript中的深拷贝和浅拷贝是前端面试中频繁被问到的一道题, 于是我也自己去查阅了一些资料, 然后动手敲了代码测试了一下。那么我就用我的理解,给大家来讲解一下这个深拷贝和浅拷贝吧。

正文

一、简单介绍

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

  • 基本类型值: 是指StringNumberundefinedNullboolean等,他们在内存中都是存储在栈中的 , 即直接访问该变量就可以得到存储在栈中的该变量的值。 若将一个变量的值赋值给另一个变量, 则这两个变量在内存中是独立的, 修改其中一个变量的值, 不会影响另一个变量。

我们来看一下图片介绍:

  1. 创建了第一个变量 a , 并赋值一个 ’ 哈哈 ’ 给它,则在内存中的表现形式为:
在这里插入图片描述
在这里插入图片描述
  1. 然后又创建了一个变量 b ,将 变量 a赋值给b,则此时在内存中的表现形式为:
在这里插入图片描述
在这里插入图片描述

可以看到在栈中, b独立占有一个位置,并且拥有自己的值,为 ’ 哈哈 ’

  1. 然后此时我们将变量a 的值改为 ’ 嘿嘿 ’ , 此时在内存中的情况是:
在这里插入图片描述
在这里插入图片描述

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

  • 引用类型值:是指ObjectArrayFunction等,他们在内存中是存在于栈与堆中, 即我们要访问到引用类型值的话, 需要先访问到该变量在栈中的地址(指向堆中的值), 然后再通过这个地址,访问到存放在堆中的数据。
  1. 我们先创建一个变量 a ,并赋值一个{name: '张三'},此时在内存中的情况就是:
在这里插入图片描述
在这里插入图片描述

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

  1. 然后我们再创建一个变量b,将变量a 赋值给变量b,此时内存中的情况是:
在这里插入图片描述
在这里插入图片描述

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

  1. 最后我们 改变一下变量a 中的值, 即a.name = ' 李四 ', 此时内存中的情况是:
在这里插入图片描述
在这里插入图片描述

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

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

二、浅拷贝

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

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

我们来看一个最简单的浅拷贝例子:

代码语言:javascript
复制
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)
console.log(b)
// { name: '李四', age: 19, like: [ '睡觉', '唱歌', '跳舞' ] }
// { 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: 被拷贝的对象
代码语言:javascript
复制
let a = {name: '张三', age: 19, like: ['打篮球', '唱歌', '跳舞']}
let b = {}
Object.assign(b, a)
a.name = '李四'
a.like[0] = '睡觉'
console.log(a)
console.log(b)
// { name: '李四', age: 19, like: [ '睡觉', '唱歌', '跳舞' ] }
// { name: '张三', age: 19, like: [ '睡觉', '唱歌', '跳舞' ] }

二、深拷贝

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

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

  • 递归拷贝

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

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

  • 利用JSON函数深拷贝 实现原理: 将变量的值转变成字符串形式, 然后再转化成对象赋值给新的变量
代码语言:javascript
复制
let a = {name: '张三', age: 19, like: ['打篮球', '唱歌', '跳舞']}
let b = JSON.parse(JSON.stringify(a))

a.name = '李四'
a.like[0] = '睡觉'

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

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

结束语

好了,我已经尽可能用易懂的语言来讲述深拷贝和浅拷贝的区别了, 这也是我研究了好久,才弄明白的, 希望不懂的你们可以理解这两个概念, 如果有什么地方讲的不好, 也欢迎大家提出来,让我改正, 谢谢~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 浅显易懂的介绍Javascript中的深拷贝和浅拷贝
  • 引言
  • 正文
    • 一、简单介绍
      • 二、浅拷贝
        • Object.assign
      • 二、深拷贝
      • 结束语
      相关产品与服务
      对象存储
      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档