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 原生的数据类型(非自定义数据类型)。

而且存在问题

  1. 会忽略 undefined
  2. 会忽略 symbol
  3. 不能序列化函数
  4. 不能解决循环引用的对象
posted @ 2023-01-23 21:43  Davy-Chen  阅读(41)  评论(0编辑  收藏  举报