遇到的问题
在一个前端项目中,我遇到了一个有趣的问题。我试图使用两个数组来模拟从前端获取数据的过程,其中一个数组 list1 包含大量数据,我尝试通过赋值的方式将其赋给另一个空数组 list2。
const list1 = ref([-----一些数据-----])
const list2 = ref([])
//要取值时,当时我打算使用赋值的办法
list2 = list1
然而这时候问题就出现了,当我对list2中进行某一项的删除这个动作的时候,原来的list1中的那一项也被我删除了,那么为什么会有这种情况出现呢?
猜想:深浅拷贝的问题
由于一开始我对基本概念的理解不够,我认为是深浅拷贝导致了这个问题,因为浅拷贝是共用一个引用,我修改其中一个的属性是会影响到另一个的,我感觉是这个问题导致的
后面,当我使用了扩展运算符来进行拷贝,这种现象又消失了,代码逻辑也正常了
list2 = [...list1]
对于这个bug,到这里就解决了,但是还有一个很大的疑问没解决,扩展运算符可是属于浅拷贝呀(如果想了解更多扩展运算符的内容,可以看我这篇博客),我之前的猜想可是深浅拷贝才导致的这个问题,那为什么共用同一个引用,list2的改变对list1没有影响呢?
深入研究: 原来引用类型是赋值不是我理解的“赋值”
后来我终于知道了,对于基本数据类型,赋值才是拷贝,而对于引用数据类型,赋值是引用的传递
list2 = list1不是拷贝操作,而是将list2引用指向与list1相同的对象。这意味着两个变量实际上引用相同的数组对象,而不是创建一个新的副本。因此,对其中一个变量所引用的数组进行修改会影响到另一个变量。
而对于拷贝来说:拷贝通常指的是创建一个新的副本,使得被拷贝的数据在新的变量或内存空间中独立存在。在计算机科学中,拷贝是复制数据的过程,创建了原始数据的一个副本,而不是引用原始数据。
那么为什么浅拷贝了一个数组,对于使用却没有影响呢?
在Vue.js中,使用
ref创建的响应式对象是具有value属性的包装对象。当你直接使用list2 = list1时,实际上是将list2指向了和list1相同的响应式对象。因此,它们引用同一个数组。如果你想要在
list2中维护一个与list1相同的数组,但又希望它们是两个独立的数组,你需要使用扩展运算符或其他方法进行浅拷贝。当你使用扩展运算符时,它确实是浅拷贝,但在Vue.js中,这种情况下浅拷贝是足够的,因为Vue.js会通过监视数组的变化来进行响应式更新。这意味着,即使你修改了
list2中的数组元素,Vue.js会检测到这个变化并更新视图,但不会影响到list1中的数组元素。示例代码:
const list1 = ref([/* 有内容 */]); const list2 = ref([...list1.value]); // 使用扩展运算符进行浅拷贝 // 修改 list2 中的数组元素 list2.value.splice(index, 1); // 这样只会影响 list2,而不会影响 list1在这个例子中,修改
list2中的数组元素不会影响list1,因为它们引用两个独立的数组对象。总结一下,虽然扩展运算符进行的是浅拷贝,但在Vue.js中,由于Vue.js的响应式系统的工作方式,这种浅拷贝足以确保在两个响应式对象中维护相互独立的数组。
总的来说,这个问题的根本在于了解赋值对于引用类型的行为,以及在特定情境下选择合适的拷贝方法。希望这篇博客能够帮助你更深入地理解JavaScript中引用类型的赋值行为以及在Vue.js中处理响应式对象时的注意事项。