背景
某天测试提了个bug,问题是这样的:页面根据物品类型展示的汇总数据是正确的,但是非汇总数据(按照TO单)物料数据有误。哎呀,赶紧去看代码,由于这块是从其他人那边接手过来的,找到代码所在之后,看了下处理逻辑:从后台拿过来的数据是按照TO单来的,前台遍历了数据里的TO单物料字段(一个数组对象),按照物料类型进行了数据汇总。
问题原因
经过分析后,发现问题就出来汇总那里,汇总的数据是直接在某个类型的第一个物料基础上进行求和计算的,这就导致了汇总处理之后,TO单里的各种类型的第一个物料的数据变成了汇总后的数据,后面的其他物料数据不受影响。这个就是典型的JS引用类型直接赋值(赋值引用即浅拷贝)导致的问题了。
问题解决
由于数组里的对象不是复杂的对象,只是简单的一层结构,所以遍历数组时使用Object.assign方法实现物料对象的深拷贝,这样后续的处理就不会影响到原始数据了。
聊聊深浅拷贝
-
什么是深浅拷贝 先说说值类型和引用类型: 值类型:数据存储在栈内存中,一个变量向另一个变量赋值,会在栈内存中创建一个副本,即拷贝实例(深拷贝),这种情况下,改变其中一个值,不会影响到另一个值。 引用类型:数据存储在堆内存中,引用类型变量存储的实际是一个指向数据对象的指针,一个变量向另一个变量赋值时,复制的是指针地址,即拷贝引用(浅拷贝),这样,两个变量最终指向的是同一个指针,当改变其中一个变量时,另一个变量自然也改变了。
-
浅拷贝实现 数组、对象等引用类型的通过赋值操作符=可以实现浅拷贝
var arr1 = [1,2,3]; var arr2 = arr1; arr2[1] = 5; console.log(arr1); //[ 1, 5, 3 ]可以看到通过修改arr2的值,arr1的值也跟着发生了变化
-
深拷贝实现 先提供一个终极解决方案,lodash工具,lodash提供的cloneDeep方法,会递归拷贝传入的值,实现深拷贝,有兴趣的,可以看下lodash是怎么实现的。接下来看下各种引用类型在数据结构不是很复杂的情况下,不引用其他插件,如何实现深拷贝。
- 数组的深拷贝
- 数组遍历赋值,如果存在多维数组就不通用了
- 一些数组方法,适用简单数组
Array.slice(0) Array.map(function(item){ return item }) Array.concat()- ES6拓展运算符,适用简单数组,数组里元素是对象等就不生效了 var [...arr2] = arr;
- JSON.stringify()、JSON.parse(),不考虑数组里有function、undefined等不能被文本化的类型; var arrDeepCopy = JSON.parse(JSON.stringify(arr));
- 对象的深拷贝
- 简单粗暴:循环遍历赋值新对象
- 对象的方法:Object.assign(),对象存在多层不适用
- JSON.stringify()、JSON.parse()
持续更新中...