面试官:什么是深拷贝,如何实现?

大家好,今天给大家带来一道常考的面试题。

深拷贝

所谓深拷贝,简单来说,就是将一个东西原模原样的复制一份下来,并且如果我们改变了我们所复制下来的内容,并不会改变原来的样本。举个例子,老师布置了一份作业,我将题目抄了下来,然后你拿我的题目抄了一份(拷贝了一份),然后你写了一份答案(拷贝的内容有所改变),你的答案并不会出现在我的作业里面(不会改变原来的样本)。

实现

要怎么实现一个深拷贝呢?这还不简单,直接上代码:

javascript 复制代码
function copy(msg) {
    return msg
}
let num = 123
let copyNum = copy(num)
console.log(num); // 123
console.log(copyNum); // 123

直接返回我们需要拷贝的数据不就好了,简简单单,看起来没什么毛病,但实际上对于对象而言,我们拷贝的实际上只是对象的引用,因为我们在调用栈中只能找到对象的引用,其实际内容存在在堆中。

css 复制代码
let obj = {
    a: 1,
    b: {
        hobby: 'coding'
    }
}
let copyObj = copy(obj)
copyObj.a = 2
console.log(obj); // { a: 2, b: { hobby: 'coding' } }
console.log(copyObj); // { a: 2, b: { hobby: 'coding' } }

我们发现当我们拷贝的内容发生变化时,原样本的值也会发生变化,这就不是深拷贝了,上面也说了,我们这样做,拷贝的其实只是对象的引用,通过该引用修改的数据其实是同一份数据。所以,我们应该怎么做呢?

  • 如果不是对象,我们直接返回,完全没毛病
  • 如果是对象,我们就应该遍历这个对象,并将其赋值给一个空对象返回出来
css 复制代码
function copy(msg) {
    if (typeof msg !== 'object' || msg === null) {
        return msg
    } else {
        const copyMsg = Array.isArray(msg) ? [] : {}
        for(let i in msg) {
            copyMsg[i] = msg[i]
        }
        return copyMsg
    }
}
let obj = {
    a: 1,
    b: {
        hobby: 'coding'
    }
}
let copyObj = copy(obj)
copyObj.a = 2
console.log(obj); // { a: 1, b: { hobby: 'coding' } }
console.log(copyObj); // { a: 2, b: { hobby: 'coding' } }

是这样吗,感觉没毛病对吧,我们改变了copyObj的内容,obj确实没有发生变化,好像两份数据互不干扰,确实有点深拷贝的味道了。实际上,我们还是遗漏了一个点,也是最容易犯错的一个点,我们来看,obj中的b是一个对象,上面也说了,我们从调用栈取对象,拿到的实际上是对象的引用,所以,两份数据中拿到的都是同一个引用(数据的地址),如果修改数据的话,修改的就是同一份数据了。

ini 复制代码
let copyObj = copy(obj)
copyObj.a = 2
copyObj.b.hobby = 'shopping'
console.log(obj); // { a: 1, b: { hobby: 'shopping' } }
console.log(copyObj); // { a: 2, b: { hobby: 'shopping' } }

你看两份数据的hobby都改了,那么怎么解决这个问题呢?这是不是和上面的问题是一样的呀,咱继续遍历里面的这个对象不就好了。那么还有一个问题,咱也不知道里面嵌套了多少个对象呀,大问题里面有相同的小问题,那不就是递归吗,是的,问题解决了。

javascript 复制代码
function copy(msg) {
    if (typeof msg !== 'object' || msg === null) {
        return msg
    } else {
        const copyMsg = Array.isArray(msg) ? [] : {}
        for(let i in msg) {
            copyMsg[i] = copy(msg[i])
        }
        return copyMsg
    }
}

let obj = {
    a: 1,
    b: {
        hobby: 'coding'
    }
}
let copyObj = copy(obj)
copyObj.a = 2
copyObj.b.hobby = 'shopping'
console.log(obj); // { a: 1, b: { hobby: 'coding' } }
console.log(copyObj); // { a: 2, b: { hobby: 'shopping' } }

哎呀!!! 问题解决,你说完美是不是。好了今天的分享就到这。

假如您也和我一样,在准备春招。欢迎加我微信shunwuyu,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!

相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
uhakadotcom9 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
快速开始使用 n8n
后端·面试·github
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github