目录
1.问题
2.解决方案
3.前端中的深拷贝及浅拷贝问题总结
1.问题
在子组件中通过emit调用父组件的方法,并传递参数,当子组件中修改传递给父组件的参数时,即使没有将修改后的值传递给父组件,父组件中的值依然修改了。
原因是传递的参数是一个对象,是引用类型,父组件中定义的变量存储的是引用类型的地址,双方指向同一个内存地址,所以只要有一方改变,另一方也会随之改变。
2.解决方案
①JSON.parse(JSON.stringify(obj))
使用JSON进行处理,但是这种简单粗暴的方法有其局限性。当值为 undefined、function、symbol 会在转换过程中被忽略。所以,对象值有这三种的话用这种方法会导致属性丢失。
②进行深拷贝处理
3.前端中的深拷贝及浅拷贝问题总结
①简单对象的深拷贝及浅拷贝
// 简单对象的浅拷贝let obj1 = {id: '1', name: '小孙', age: 18}let obj2 = obj1console.log(obj1 === obj2) // true 代表两个对象是同一个实例,对应内存中同一个内存地址,一方修改另一方随之改变obj1.id = '2'console.log(obj2) //Object { id: "2", name: "小孙", age: 18 }obj2.name="小林"console.log(obj1) //Object { id: "2", name: "小林", age: 18 }// 简单对象的深拷贝let obj3 = {...obj1}console.log(obj1 === obj3) // falselet obj4 = Object.assign({}, obj1)console.log(obj1 === obj4) // false
深拷贝中可以使用扩展运算符,生成新的对象,也可以使用Object的assign方法
扩展运算符说明:是三个点(...),它可以用于展开,复制,合并数组或者对象。如果有重复的内容,后面的覆盖前面的。当使用扩展运算符展开一个对象时,会创建一个新的对象,两个对象之间是独立的没有任何关联。
展开
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5, 6];
console.log(arr2); // 输出:[1, 2, 3, 4, 5, 6]合并
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combinedArr = [...arr1, ...arr2];
console.log(combinedArr); // 输出:[1, 2, 3, 4, 5, 6]复制
const arr1 = [1, 2, 3];
const arr2 = [...arr1];
console.log(arr2); // 输出:[1, 2, 3]
②简单数组的深拷贝和浅拷贝
// 简单数组的浅拷贝let arr1 = ['1', '2', '3', '4']let arr2 = arr1console.log(arr1 === arr2) // true 代表两个对象是同一个实例,对应内存中同一个内存地址// 简单数组的深拷贝let arr3 = arr1.concat()console.log(arr1 === arr3) // falselet arr4 = arr1.slice(0)console.log(arr1 === arr4) // falselet arr5 = Object.assign([], arr1)console.log(arr1 === arr5) // falselet arr6 = [...arr1]console.log(arr1 == arr6) // false
③复杂对象的深拷贝及浅拷贝
// 复杂对象中的外层对象的深拷贝,内层对象或数组的浅拷贝let obj10 = {info:{id:'1',name:'小李',age:25},ke:['1','2','3','4']}let obj11 = {...obj10}console.log(obj10 === obj11) // falseconsole.log(obj10.info === obj11.info) // trueconsole.log(obj10.ke === obj11.ke) // true// 如只做了外层对象或者数组的深拷贝,但是内部的对象和数组是浅拷贝,一方发生改变,另一方随之改变// 复杂对象中的外层对象的深拷贝,内层对象或数组的深拷贝let obj12 = {}Object.entries(obj10).forEach(([key,val]) =>{if(Object.prototype.toString.call(val) == '[object Object]'){obj12[key] = {...val}}else if(Object.prototype.toString.call(val) == '[object Array]'){obj12[key] = val.concat()}})console.log(obj12)console.log(obj12 === obj10) //falseconsole.log(obj10.info === obj12.info) // falseconsole.log(obj10.ke === obj12.ke) // false
需要注意的是,如果对象内嵌套数组或者对象,如果只使用扩展运算符,只是对外层的对象做了深拷贝处理,但是对象内的数组或者对象,依然是浅拷贝,所以需要循环进行处理。