深浅拷贝,看完狠狠避雷!

前提提要:

最近在开发需求时,突然遇到一个问题,我请求过来的数据,怎么还会改变呢??导致卡壳卡了许久,看完才发现,原来是你小子!!深浅拷贝。

既然哥们踩雷了,那不行,得让兄弟们有福同享。

Javascript的七种数据类型

Javascript的数据类型分为:

  • 基本数据类型
  1. 数字类型(Number)
  2. 未定义(Undefined)
  3. 字符串(String)
  4. 空(Null)
  5. 符号型(Symbol)
  6. 布尔(Boolean)
  • 引用数据类型
  1. 对象(Object)

基本数据类型(值拷贝):

StringNumberBooleannullundefinedSymbolBigInt

特点:直接存储在栈内存,赋值时创建新值

let a = 10;
let b = a; // 创建新值
b = 20;
console.log(a); // 10 (不受影响)

引用数据类型(指针拷贝):

ObjectArrayFunctionDate, 等
特点:数据在堆内存,变量存储的是内存地址指针

let obj1 = { name: "John" };
let obj2 = obj1; // 复制指针(指向同一内存)
obj2.name = "Mike";
console.log(obj1.name); // "Mike" (原数据被修改)

什么是深浅拷贝

首先深浅拷贝是针对引用数据类型的。

浅拷贝

只复制对象的第一层属性,嵌套对象仍共享内存地址

 实现方式:

  • 扩展运算符 ...
const source = { a: 1, b: { c: 2 } };
const copy = { ...source };
copy.b.c = 3; // 修改嵌套属性
console.log(source.b.c); // 3 (原对象被修改)

//注意
copy.b.a = 2
console.log(source.a) //1 (未被修改)

可以看到 使用...运算符时,如果第一层数据是基础数据类型 ,是不会被修改的,所以如果属性都是基本类型的值,使用扩展运算符进行拷贝会更加方便。

  • Object.assign()
const copy = Object.assign({}, source);
  • slice 拷贝数组
const arr = [1, { name: "test" }];
const copy1 = arr.slice();

copy1[1].name = "a"

console.log(arr[1].name) // a

深拷贝

完全克隆对象及其嵌套对象,新旧对象完全隔离

 实现方式:

  • JSON.parse(JSON.stringify())

        缺陷

  • 丢失 undefined/Symbol/函数

  • 忽略原型链

  • 循环引用报错

  • 无法处理特殊对象(Date 变字符串、RegExp 变空对象等)

const source = { date: new Date(), fn: () => {} };
const copy = JSON.parse(JSON.stringify(source));
console.log(copy); // { date: "2023-05-15T02:...", fn 丢失 }
  • 递归实现(基础版,手动复制) 
function deepClone(source) {
  if (source === null || typeof source !== 'object') {
    return source;
  }
  const target = Array.isArray(source) ? [] : {};
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      target[key] = deepClone(source[key]);
    }
  }
  return target;
}

 应用场景选择

场景 推荐方式
无嵌套对象/数组 浅拷贝 (.../Object.assign())
需要完全隔离的复杂对象 完整版深拷贝
包含函数/Symbol/特殊对象 递归+特殊类型处理
超大数据结构 BFS 迭代深拷贝
简单数据快速克隆 JSON.parse(JSON.stringify())(需知缺陷)

我遇到的问题

一个很基础,但是容易忽视的问题

//定义数据
const arr = [
{
    check:true,
    name:"YL有搞头"
},
{
    check:true,
    name:"YL"
},
{
    check:true,
    name:"有搞头"
}]

//将arr[i]直接push进另一个数组

const newArr = []

newArr.push(arr[0])

//修改newArr的值
newArr[0].check = false

//导致arr的数据遭到修改
arr[0].check = false

//解决办法
newArr.push({...arr[0]})

 总结

  1. 基本类型:直接复制值,无深浅拷贝概念

  2. 浅拷贝:仅复制第一层,嵌套对象共享内存

  3. 深拷贝核心难点

    • 循环引用检测(WeakMap)

    • 特殊对象处理(Date/RegExp/Set/Map)

    • Symbol 属性复制

    • 原型链维护

  4. 性能优化:大数据结构建议使用 BFS 迭代

  5. 生产环境:优先使用成熟的库(Lodash 的 _.cloneDeep

你可能感兴趣的:(javascript,开发语言,前端,数据类型,深浅拷贝)