JavaScript 深浅拷贝全解析:告别引用类型的坑!

72 阅读3分钟

在 JavaScript 开发中,对象的拷贝是一个常见但又容易出错的话题。今天我们来深入探讨深浅拷贝的区别、实现方式以及使用场景。

什么是拷贝?

简单来说,拷贝就是基于原对象,创建一个新对象。但这里有个关键点:拷贝操作只针对引用类型(对象、数组、函数等),因为基本类型(字符串、数字、布尔等)的赋值本身就是值的复制。

浅拷贝:表面功夫

浅拷贝创建了一个新对象,但只复制了原对象的第一层属性。如果属性值是对象,那么拷贝的只是该对象的引用地址。

浅拷贝的特点:

  • 新对象的第一层属性修改不会影响原对象
  • 但嵌套的对象属性修改会相互影响(因为共享同一引用)

常见的浅拷贝方法

1. [].slice(0)

  • 数组里面的slice方法,接收两个参数第一个是起始下标,第二个是结束下标。只写起始下标的话就是全切一遍,并且不影响原数组得到一个新数组。
const arr = ['a', 'b', 'c', 'd', {age: 18}]
const arr2 = arr.slice(0)
arr[4].age = 20
console.log(arr2);

2. [...a]

  • 数组里面的解构方法
const a = [1, 2, {age: 18}]
// const b = [3, 4]
let c = [...a]
a[2].age = 19
console.log(c);

3. [].concat()

  • 数组的contact方法
const a = [1, 2, 3, {age: 18}]
const d = [].concat(a)
a[3].age = 20

4. arr.toReversed().reverse()

  • toReversed + reverse(较新的方法)
const arr = [1, 2, 3]
const arr2 = arr.toReversed().reverse()
console.log(arr2);

5. Object.assign({},obj)

  • Object.assign 方法
const obj={
    name:'汉堡'
}
const obj2={
    age:18
}
Object.assign(obj,obj2)
console.log(obj);

问题展示

这里浅拷贝再改变obj的值就会使得新拷贝的对象里面的值受到影响,所以这是拷贝了第一层,并没有拷贝到里面对象的引用地址。

屏幕截图 2025-12-17 183228.png

深拷贝:彻底分离

深拷贝会递归地拷贝所有层级的属性,创建一个完全独立的新对象,新旧对象之间互不影响。

常见的深拷贝方法

structuredClone -- 无法拷贝函数

const obj = {
    name: '汉堡',
    age: 18,
    like: {
        n: '洗脚',
        m: '台球'
    },
    a: 123n,

}

const newObj = structuredClone(obj)
obj.like.m = '蓝球'

console.log(newObj);

屏幕截图 2025-12-17 184315.png

JSON.parse(JSON.stringify(obj))

无法处理 bigint,undefined,NaN,Infinity,function

const obj = {
  name: '俊杰',
  age: 18,
  like: {
    n: '洗脚',
    m: '台球'
  },
  say() {
    console.log('hello');
  },
  a: undefined,
  b: null,
  c: NaN,
  d: Infinity
}

const oo = JSON.parse(JSON.stringify(obj))
obj.like.m = '篮球'

console.log(oo);

屏幕截图 2025-12-17 184712.png

手写深拷贝函数

对于更复杂的需求,我们可以自己实现一个深拷贝函数: 这里利用递归这种方法来层层拷贝要拷贝的对象

const obj = {
  name: '俊杰',
  age: 18,
  like: {
    n: '洗脚',
    m: '台球'
  }
}

function deepClone(obj) {
  let o = {}
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof(obj[key]) == 'object' && obj[key] !== null) {
        const childObj = deepClone(obj[key])
        o[key] = childObj
      } else {
        o[key] = obj[key]
      }
      
    }
  }
  return o
}

const newObj = deepClone(obj)
obj.like.m = '篮球'

console.log(newObj);

总结

适合浅拷贝的场景:

  • 对象结构简单,没有嵌套对象
  • 性能要求高(深拷贝更耗资源)
  • 明确知道不会修改嵌套属性

适合深拷贝的场景:

  • 状态管理
  • 表单数据的初始化和重置
  • 需要完全独立的对象副本
  • 处理配置对象等需要隔离的数据