结合实际工作场景深入理解Javascript深拷贝和浅拷贝的特性

项目场景:

大家在做后台管理系统的时候一定会有这种增、删、改这种需求,当然这种需求一般都是表格展示数据,最后一列是操作按钮,点击按钮会弹出操作框。如下图的这种模式:
在这里插入图片描述
在这里插入图片描述


问题描述:

但是小李最近在做的时候遇见一个问题,就是当他修改了操作框里面的值之后,还没有提交表格的数据也就被修改了,究竟是什么原因导致的?故障如图:
在这里插入图片描述


原因分析:

首先看看他写的代码是如何实现的
在这里插入图片描述

在这里插入图片描述


解决方案:

修改代码如下:

    showChangeWindow(row) {
      this.changeWindow = true; 
      this.changeData = JSON.parse(JSON.stringify(row))
    },

修改之后效果图:
在这里插入图片描述

很多同学可能会有疑问?为什么加一个JSON.parse(JSON.stringify(row))就可以解决了,要解答这个问题就会牵扯到Js的深拷贝和浅拷贝这方面的知识,下面给大家说说Js的深拷贝和浅拷贝

一、为什么会有深拷贝和浅拷贝之分?

Javascript的变量分为基本类型和引用类型两大类。当JavaScript在进行变量赋值的时候,解析器会首先确认这个变量的类型,如果是基本类型就可以直接操作保存在内存中的实际值,但是如果是引用类型就不能直接操作内存中存储数据的空间,只能通过改变他的引用(指针)去操作,所以遇到引用 类型我们实际上操作的是他的引用或者说是他的指针,并不是它实际的存储空间。产生这种差异的主要原因是因为,基本类型和引用类型存储方式不同,基本类型储存在栈中,但是引用类型的数据储存在堆中,JS不允许我们直接操作堆内存,所以只能通过操作它存储在栈中的引用(指针)去操作。为了便于大家理解上代码:

基本类型的拷贝

var num1 = 5
var num2 = num1

在这里插入图片描述

当num2复制num1的值之后,num2也保存了num1值,并且会在栈内存中开辟新的空间,用来保存num2的值,num2和num1都是完全独立,此后两个变量进行任何操作都不会互相影响。


引用类型的拷贝

var arr1 = {}
var arr2 = arr1
arr1.name = "lisi"
console.log(arr2)
输出:
lisi

在这里插入图片描述

arr1指向堆内存中存储数据的object,当arr1赋值到arr2的时候,实际上arr2拿到的只是arr1在堆内存中存储数据的指针,所以当我给arr1进行赋值的时候也会影响到arr2,就相当于是堆内存中的一个存储单元,却被栈中的两个变量(引用)访问。

这其实已经给大家从侧面描述了深拷贝和浅拷贝的主要区别:
	- 深拷贝的两个对象不会相互影响,都是属于独立的个体
	- 浅拷贝的两个对象会相互影响

二、如何实现数据的深拷贝?

Ⅰ:对象实现深拷贝的几种主要方式:

  1. JSON.parse(JSON.stringify())
//浅拷贝
var obj = {}
var obj1 = obj
obj1.name = 'li'
console.log(obj)
//深拷贝
//使用JSON.parse(JSON.stringify())之后
var ocj = {}
var ocj1 = JSON.parse(JSON.stringify(ocj))
ocj1.name = 'li'
console.log(ocj)

在这里插入图片描述

  1. Object.assign()
    注意:仅支持一级对象的深拷贝,如果对象是多级嵌套那么二级对象之间就是浅拷贝
一级对象
var obj = {name:'li'}
var cbj = Object.assign({},obj)
cbj.name = 'si'
console.log(obj)
console.log(cbj)

在这里插入图片描述

二级对象
var obj = {name:'li',info:{name:"zhang"}}
var cbj = Object.assign({},obj)
cbj.name = 'si'
cbj.info.name = 'wang'
console.log(obj)
console.log(cbj)

在这里插入图片描述

Ⅱ:数组实现深拷贝的几种主要方式::

 注意:
 	当数组中的元素均为一维时,实现深拷贝;
 	当有二维数组出现时,深拷贝数组中元素一维以上是值的引用(浅拷贝) 
  1. concat()
//均为一维数组
var arr = []
var brr = arr
brr[0] = 'li'
console.log(arr)
var crr = [].concat(arr)
crr[0] = 'wnagsi'
console.log(arr)

在这里插入图片描述

//二维数组
var arr = [1,2,3,[7,8]]
var brr = [].concat(arr)
brr[0] = 'gaibian'
brr[3].push('112')
console.log(arr)
console.log(brr)

在这里插入图片描述

  1. slice(a, b)
    参数可以省略,如果给定两个参数就是从数组的起始参数拷贝到结束参数;如果给定一个参数,那么就是从这个元素开始拷贝到数组最后。
var arr = [1,2,3,[4,5]]
var brr = arr.slice()
brr[0] = 'ces'
brr[3].push('test')
console.log(arr)

在这里插入图片描述
总结
这篇文章结合实际工作中遇到的bug,引出深拷贝和浅拷贝的知识,希望对大家学习js有帮助。
🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
☞关注博主不迷路,博主带你上高速,希望大家可以共同进步。淦👊

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值