JS基础面试高频(三):浅拷贝和深拷贝

前言

工作中可能会遇到这样一个问题,我明明把数据拷贝了一份,但改变拷贝后的数据居然同时会改变原始数据中的值。那就来看看为什么吧,希望这篇文章可以给你解惑。

什么是浅拷贝

只拷贝了数据对象的第一层,深层次的数据值与原始数据会互相影响(拷贝后的数据与原始数据还存有关联)

常见浅拷贝的方式:Object.assign()扩展运算符

const obj1 = { name: 'dog', info: { age: 3 } }
const obj2 = Object.assign({}, obj1)
// 或者
const obj2 = { ...obj1 }

obj2.name = 'cat'
obj2.info.age = 4
console.log(obj1) // { name: 'dog', info: { age: 4 } }
console.log(obj2) // { name: 'cat', info: { age: 4 } }
复制代码

当拷贝后的对象obj2数据改变的时候会影响原始数据obj1,因为info对象拷贝的是源对象指针。

不清楚指针的可以看前面的这篇文章
JS基础面试高频(一):数据类型

什么是深拷贝

不管数据对象有多少层,改变拷贝后的值都不会影响原始数据的值。(拷贝后的数据与原始数据毫无关系)

常见深拷贝的方式:JSON.parse()JSON.stringify()配合使用

const obj1 = { name: 'dog', info: { age: 3 }, fn: function () {} }
const obj2 = JSON.parse(JSON.stringify(obj1))
obj2.name = 'cat'
obj2.info.age = 4
console.log(obj1) // { name: 'dog', info: { age: 3 }, fn: function(){} }
console.log(obj2) // { name: 'cat', info: { age: 4 } }
复制代码

这种方式有一个弊端,就是无法正确处理函数正则


我们也可以手写一个深拷贝的方法(简易基础版)

function deepClone(source) {
  // null数据需要特殊处理
  if (source === null) {
    return source
  }
  // 校验要拷贝的数据是对象还是数组
  const target = Array.isArray(source) ? [] : {}
  for (const k in source) {
    const val = source[k]
    const valueType = typeof val
    // 校验拷贝的数据类型
    if (valueType === 'function') {
      target[k] = new Function(`return ${val.toString()}`)()
    } else if (valueType === 'object') {
      target[k] = deepClone(val)
    } else {
      target[k] = val
    }
  }
  return target
}

const obj1 = { name: 'dog', info: { age: 3 }, fn: function () {} }
const obj2 = deepClone(obj1)
obj2.name = 'cat'
obj2.info.age = 4
console.log(obj1) // { name: 'dog', info: { age: 3 }, fn: function(){} }
console.log(obj2) // { name: 'cat', info: { age: 4 }, fn: function(){} } 
复制代码

当然还可以使用第三方库Lodash中的_.cloneDeep(value),强烈推荐这个库,功能非常强大!


关注公众号【麋鹿迷了路】,发送js获取更多学习资源 喜欢的小伙伴们点个赞吧O(∩_∩)O

本文使用 mdnice 排版

分类:
前端
标签: