深拷贝和浅拷贝
一般拷贝的使用场景主要是,将对象或者数组赋值到新的变量中。但是这样就会出现一个问题,当改变新的对象或数组时,源数组或对象也会发生改变,那么这个时候要根据实际情况使用深度拷贝,还是浅拷贝,这里不能一股脑的使用深度拷贝,毕竟深度拷贝对于性能的消耗还是蛮大的
对于像forEach、map、filter 如果操作的是基本数据类型则不会影响原始数据,一旦是对象、数组这种引用类型的,那么操作数据同样会影响原始数据
区别
浅拷贝: 将原对象或者原数组直接赋给新的变量,这里赋值的对象或者数据的引用,他们内存中指向的地址是一个,所以新变量的值进行改变,其原对象或者数组也会发生改变
深拷贝: 将原对象或者原数组的值赋给新的变量中,这里是赋值的值,而不是引用,那么当新变量的值发生改变,原对象或数组不会发生改变
使用
浅拷使用
循环遍历赋值
循环遍历数组进行赋值
let array = [1, 2, 3, 4]
let newArray = [];
array.forEach((item) => {
newArray.push(item)
})
newArray[0] = 10
console.log("原数组==>>"+array)
console.log("新数组==>>"+newArray)
效果:
不是说是浅拷贝吗,改变新数组,原数组会改变吗,这里为什么并没有达到预期?
**原因:**虽然原数组是一个引用类型,但因为遍历数组赋值的是数值类型(基本类型),所以并不会产生同一个引用。所以才有上述的情况
直接进行赋值就会发生改变
let array = [1, 2, 3, 4]
let newArray = [];
newArray=array;
newArray[0] = 10
console.log("原数组==>>"+array)
console.log("新数组==>>"+newArray)
效果:
或者数组对象
let array = [{
num: 1
}, {
num: 2
}, {
num: 3
}, {
num: 4
}]
let newArray = [];
array.forEach(i => {
newArray.push(i)
})
newArray[0].num = 10
console.log(`原数组==>>${JSON.stringify(array)}`)
console.log(`新数组==>>${JSON.stringify(newArray)}`)
可以看到这里直接赋值,而因为产生同一个引用,所以产生了原数组改变的预期:
slice
slice() 方法可从已有的数组中返回选定的元素。返回一个新数组
let array = [{
num: 1
}, {
num: 2
}, {
num: 3
}, {
num: 4
}]
let newArray = array.slice();
newArray[0].num = 10
console.log(`原数组==>>${JSON.stringify(array)}`)
console.log(`新数组==>>${JSON.stringify(newArray)}`)
效果:
可以看到数组对象情况下修改新数组,原数组会改变,该方法和第一种遍历的方法是同样的效果。其中如果数数组数值非引用类型,就不会改变原数组
concat
方法用于连接两个或多个数组。
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
let array = [{
num:1
},{
num:2
},{
num:3
},{
num:4
}]
let newArray = array.concat();
newArray[0].num = 10
console.log(`原数组==>>${JSON.stringify(array)}`)
console.log(`新数组==>>${JSON.stringify(newArray)}`)
预期和上述是一致的
Object.assign
用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
let obj={
name:"浅拷贝"
}
let newObj=Object.assign({},obj);
newObj.name="新拷贝"
console.log(`原数组==>>${JSON.stringify(obj)}`)
console.log(`新数组==>>${JSON.stringify(newObj)}`)
这里的数据其实和上面方法的数据有个共同点,1层结构,那么我改变新数组或对象的值不会对源数据产生影响
多层:
let obj={
name:{
nick:"nick"
}
}
let newObj=Object.assign({},obj);
newObj.name.nick="newNick"
console.log(`原数组==>>${JSON.stringify(obj)}`)
console.log(`新数组==>>${JSON.stringify(newObj)}`)
这里其他的方式就不做赘述了
深拷使用
JSON.parse(JSON.stringify())
使用json.stringify()转成一个字符串,然后再用json.parse()转成新的对象
但是这种方式只有可以转成Json对象的数据才可以使用,Function等无法转成Json对象的就不能使用
强大的lodash库
具体使用可以参考官方文档
深度递归
深度递归,递归每层,如果是引用类型那么就去继续递归,直到遇到是数值类型的,然后进行赋值,否则直接赋值
immutable
该库提供了众多的api,来实现深度拷贝
官网