likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 4

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

深拷贝

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

实现

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

function copy(msg) {
    return msg
}
let num = 123
let copyNum = copy(num)
console.log(num); // 123
console.log(copyNum); // 123

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

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' } }

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

  • 如果不是对象,我们直接返回,完全没毛病
  • 如果是对象,我们就应该遍历这个对象,并将其赋值给一个空对象返回出来
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是一个对象,上面也说了,我们从调用栈取对象,拿到的实际上是对象的引用,所以,两份数据中拿到的都是同一个引用(数据的地址),如果修改数据的话,修改的就是同一份数据了。

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都改了,那么怎么解决这个问题呢?这是不是和上面的问题是一样的呀,咱继续遍历里面的这个对象不就好了。那么还有一个问题,咱也不知道里面嵌套了多少个对象呀,大问题里面有相同的小问题,那不就是递归吗,是的,问题解决了。

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,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!