项目场景:
大家在做后台管理系统的时候一定会有这种增、删、改这种需求,当然这种需求一般都是表格展示数据,最后一列是操作按钮,点击按钮会弹出操作框。如下图的这种模式:
问题描述:
但是小李最近在做的时候遇见一个问题,就是当他修改了操作框里面的值之后,还没有提交表格的数据也就被修改了,究竟是什么原因导致的?故障如图:
原因分析:
首先看看他写的代码是如何实现的
解决方案:
修改代码如下:
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,就相当于是堆内存中的一个存储单元,却被栈中的两个变量(引用)访问。
这其实已经给大家从侧面描述了深拷贝和浅拷贝的主要区别:
- 深拷贝的两个对象不会相互影响,都是属于独立的个体
- 浅拷贝的两个对象会相互影响
二、如何实现数据的深拷贝?
Ⅰ:对象实现深拷贝的几种主要方式:
- 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)
- 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)
Ⅱ:数组实现深拷贝的几种主要方式::
注意:
当数组中的元素均为一维时,实现深拷贝;
当有二维数组出现时,深拷贝数组中元素一维以上是值的引用(浅拷贝)
- 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)
- 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有帮助。
🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
☞关注博主不迷路,博主带你上高速,希望大家可以共同进步。淦👊