一、问题描述
项目里新添加了一个多选的功能,其显示的数据都是从后端返回过来的,通过for循环显示出来。我们需要在返回来的数据外再额外添加一个是否选中的标记,我的选择是在返回正确的数据时将是都选择的标记添加进去,然后push到数组中。
在测试的时候出现了bug,即任意勾选其中一条数据都会导致其他的数据一起被勾选,而且其他显示的内容如果改变了,也会全部改变。原本以为是select选择器写的有问题,就把数据全部改成了测试的固定数据,发现并不会出现问题,才开始怀疑是不是由于所有的数据都指向同一个内存导致的。
二、问题代码
<!--通过循环数组将返回来的对象显示出来--> <template v-for="(list, index ) in prodCategoryListShow"> <showdiv :key="index" :iskey="index" @click="del" :prodCategory="list.prodCategory" :prodType="list.prodType" :level="list.level" :period="list.period" :reftRate="list.reftRate" :isChecked="list.isChecked" ></showdiv> </template>
错误代码:
//在data中定义对象 data () { return { prodCategoryOneShow: {} } }
//请求回来后判断是否成功,成功后将数据放入data中定义的对象里 if (res.data.resCode === AjaxReturnState.success) { this.prodCategoryOneShow.prodCategory = res.data.data.prodCategory; this.prodCategoryOneShow.prodType = res.data.data.prodType; this.prodCategoryOneShow.level = res.data.data.level; this.prodCategoryOneShow.period = res.data.data.period; this.prodCategoryOneShow.reftRate = res.data.data.reftRate; //在对象里添加是否选中的标志isChecked,一进去默认未选中 this.prodCategoryOneShow.isChecked = false; //将每次请求回来的一个对象添加到数组里 this.prodCategoryListShow.push(this.prodCategoryOneShow); }
错误分析:每一次请求后,我将得到的对象属性的值一条一条塞进prodCategoryOneShow对象里。由于拿到是基本类型,将基本类型的值一条一条的放入对象里,这样导致的结果是,我每一次请求后塞进的prodCategoryOneShow对象都指向的是同一个内存地址,而且数据都是一样的(地址指向即第一次在data中申明的prodCategoryListShow的内存)。所以,我对数组里的任何一个对象进行操作,都会影响到其他的对象的内容。
三、解决方案
if (res.data.resCode === AjaxReturnState.success) { //直接将请求回来的数据赋值给data里的对象 this.prodCategoryOneShow = res.data.data; this.prodCategoryOneShow.isChecked = false; this.prodCategoryListShow.push(this.prodCategoryOneShow); }
这样子修改后,每一次请求成功后,将data对象简单赋值给prodCategoryOneShow,prodCategoryOneShow的内存地址指向和data保持一致。因为每一次请求后得到的对象(res.data.data)地址指向都不同,所以将其赋值给data中的对象,每一次的值西也不同,继而对数组中的对象任意对象操作不会影响到其他对象。
四、其他方案
对象间的赋值(深拷贝)
obj1=JSON.parse(JSON.stringify(obj2));
首先将obj2对象利用JSON.stringify()方法转换成字符串去掉对象属性,再使用JSON.parse()方法转换成对象赋值;
其作用是避免对象直接赋值造成指向相同地址以至于相互影响的问题。