# 深拷贝

对于对象的拷贝,存在浅拷贝和深拷贝的区别。

const obj = {
  name: {
    first: 'san',
    last: 'zhang',
  },
  age: 20,
}

const arr = [{ first: 'san', last: 'zhang' }, 20]

# 浅拷贝

对于对象obj,浅拷贝只拷贝一级属性,如果属性值又是一个对象,则只会拷贝相应的引用。

# Object.assign

const obj1 = Object.assign({}, obj)
obj.name.first = 'si'
console.log(obj1.name.first) // si

const arr1 = Object.assign([], arr)
arr[0].first = 'si'
console.log(arr1[0].first) // si

# 扩展运算符

const obj1 = { ...obj }
obj.name.first = 'si'
console.log(obj1.name.first) // si

const arr1 = [...arr]
arr[0].first = 'si'
console.log(arr1[0].first) // si

# 数组切片

const arr1 = arr.slice()
arr[0].first = 'si'
console.log(arr1[0].first) // si

# 数组拼接

const arr1 = arr.slice()
arr[0].first = 'si'
console.log(arr1[0].first) // si

# 深拷贝

不同于浅拷贝,深拷贝会递归拷贝所有嵌套对象。

# JSON拷贝

const obj1 = JSON.parse(JSON.stringify(obj))
obj.name.first = 'si'
console.log(obj1.name.first) // san

const arr1 = JSON.parse(JSON.stringify(arr))
arr[0].first = 'si'
console.log(arr1[0].first) // san

JSON拷贝的问题: 不能拷贝方法、undefined和Symbol属性

const testObj = {
  eat() {
    console.log('eat')
  },
  [Symbol()]: 'test',
  name: undefined,
}
const obj1 = JSON.parse(JSON.stringify(testObj))
console.log(obj1) // {}

# 递归遍历

function deepCopy(obj) {
  // 判断是否为数组
  const clone = Array.isArray(obj) ? [] : {}
  // 判断是否为空对象
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      // 拷贝自有属性
      if (obj.hasOwnProperty(key)) {
        // 属性值为对象则递归拷贝
        if (obj[key] && typeof obj[key] === 'object') {
          clone[key] = deepCopy(obj[key])
        } else {
          clone[key] = obj[key]
        }
      }
    }
  }
  return clone
}

const obj1 = deepCopy(obj)
obj.name.first = 'si'
console.log(obj1.name.first) // san

const arr1 = deepCopy(arr)
arr[0].first = 'si'
console.log(arr1[0].first) // san

由于for in 不会遍历Symbol,这里的实现忽略了Symbol

const testObj = {
  eat() {
    console.log('eat')
  },
  [Symbol()]: 'test',
  name: undefined,
}
const obj2 = deepCopy(testObj)
console.log(obj2) // { eat: [Function: eat], name: undefined }

# lodash.cloneDeep

const _ = require('lodash')

const obj1 = _.cloneDeep(obj)
obj.name.first = 'si'
console.log(obj1.name.first) // san

const arr1 = _.cloneDeep(arr)
arr[0].first = 'si'
console.log(arr1[0].first) // san

lodash.cloneDeep覆盖了所有可迭代属性

const testObj = {
  eat() {
    console.log('eat')
  },
  [Symbol()]: 'test',
  name: undefined,
}

const obj3 = _.cloneDeep(testObj)
console.log(obj3) // { eat: [Function: eat], name: undefined, [Symbol()]: 'test' }
上次更新: 2/13/2025, 3:29:47 AM