JS深拷贝与浅拷贝
参考:https://juejin.cn/post/6844903830665035789
浅拷贝---浅拷贝是指复制对象的时候,只对第一层键值对进行独立的复制,如果对象内还有对象,则只能复制嵌套对象的地址
深拷贝---深拷贝是指复制对象的时候完全的拷贝一份对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。其实只要递归下去,把那些属性的值仍然是对象的再次进入对象内部一 一进行复制即可。
引发深浅拷贝的一些问题
变量包含两种不同数据类型的值,基本类型和引用类型两种,基本类型就包括 String,Number,Boolean,Null,Undefined和Symbol,引用类型值指那些可能由多个值构成的对象,具体如下:
Object(Object、Array、Function)
当基本类型传递时,就是按值传递,不存在深浅拷贝的问题例如:
let a = 10; // 定义一个变量a并赋值为10
let b = a; // 将a的值10赋值给b (a、b都是基本类型,值传递)
b++; // b自加
console.log(a, b) // 10, 11
但是引用类型则是地址传递,将存放在栈内存中的地址赋值给接收的变量。
let a = ['a', 'b', 'c']; // 定义一个数组a并赋值
let b = a; // 数组是引用类型,采用地址传递,将a的地址赋值给b
b.push('d'); // 给b数组增加一个'd'元素
console.log(a) // ['a', 'b', 'c', 'd']
console.log(b) // ['a', 'b', 'c', 'd']
为了解决这个引用的问题,就出现了深浅拷贝。
浅拷贝常用方法
利用assign
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
// 将source拼接到target中,重合部分则保留target部分
console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target);
// expected output: true
利用spread运算符
const a = {
en: { c: 'Bye' },
de: 'Tschüss'
}
let b = { ...a }
b.de = 'Ciao';
b.en.c = 'aaa';
console.log(b.de) // Ciao
console.log(a.de) // Tschüss
console.log(b.en.c); // aaa
console.log(a.en.c); // aaa
但是要注意,浅拷贝只能拷贝第一层!上述代码中a对象中en的c在第二层,就被按地址传值,所以改ba也会变。
深拷贝常用方法
JSON.parse(JSON.stringify(target))
const a = {
foods: {
dinner: 'Pasta'
}
}
let b = JSON.parse(JSON.stringify(a))
b.foods.dinner = 'Soup'
console.log(b.foods.dinner) // Soup
console.log(a.foods.dinner) // Pasta
但是这里要注意的是,你只能使用这种方法拷贝 JavaScript 原生的数据类型(非自定义数据类型)。
而且存在问题:
- 会忽略 undefined
- 会忽略 symbol
- 不能序列化函数
- 不能解决循环引用的对象