前端面试高频考点之——深拷贝和浅拷贝

7,180 阅读3分钟

引言

  在前端开发中,经常会遇到需要复制对象或数组的情况。这时候就会用到深拷贝和浅拷贝的概念。深拷贝和浅拷贝是前端面试中的高频考点,理解它们的区别和应用场景对于面试以及日常开发都非常重要。本文将详细介绍深拷贝和浅拷贝的概念、区别以及常见的实现方式。

 

正文

通常我们在聊到深拷贝的浅拷贝的时候,聊得一般都是引用类型的值,比如对象和数组,而原始类型的值我们一般是不聊的,因为原始类型的值无一例外都是深拷贝。

浅拷贝

大家都知道,引用类型的值都是存在堆中而不是栈中。浅拷贝是指在复制对象或数组时,只复制一层对象的引用而不是实际的对象本身。也就是说,新对象与原对象共享同一个内存地址,其中一个对象的修改会影响到另一个对象。

let a = {
    age:18
 }
 let b = a
//  b的age会随着a的age的改变而改变,这就叫浅拷贝
 a.age=20
 console.log(b.age);//20

  实际上常见的拷贝方法几乎都是浅拷贝,对象身上的赋值运算,Object.assign(),Object.created(),数组的解构,concat,slice以及arr.toReversed().reverse()等都是浅拷贝。那么,就不存在深拷贝的方法了吗?显然是存在的

深拷贝

什么是深拷贝? 深拷贝是指在复制对象或数组时,不仅复制对象本身,还要递归地复制对象的所有子对象,使得新对象与原对象完全独立,互不影响。目前的话就原生js中,引用类型的深拷贝就只有通过将对象转为字符串,再把字符串转为对象这一方法被广泛使用。

let obj = { name: 'Alice', age: 20 };

let newObj = JSON.parse(JSON.stringify(obj));

通常情况下,这种方法能够很好地对引用类型的值进行深拷贝,但遗憾的是,使用 JSON.stringify() 和 JSON.parse() 进行深拷贝时,会忽略 undefined、Symbol 和函数等特殊值。导致无法拷贝,并且,若尝试拷贝bigInt类型的值或者是循环引用的数据,会直接报错。

let obj = {
    name: '我真的很困',
    like: {
        type: 'coding',
        a: undefined,
        b: null,
        c: function () {
            console.log('hello');
        },
        e: Symbol('hello'),
// acef都拷贝不了
    }
}
let newObj= JSON.parse(JSON.stringify(obj))
console.log(newObj);

1.png

//尝试深拷贝bigInt类型
let obj={
    a:123n
}
let newObj= JSON.parse(JSON.stringify(obj))
console.log(newObj);

1.png

说到这里就不得不提一下lodash这个库了,lodash提供了cloneDeep()方法,允许我们对引用类型的值进行深拷贝,并且不会出现上面的情况。

const dc = require('lodash');
let obj = { name: 'Alice', age: 20 };
let newObj = dc.cloneDeep(obj);

不过据说还有另一种方法 ,但可惜目前好像除了谷歌浏览器以外没有支持的浏览器的,属于是剑走偏锋出奇效的了。本文不做讲解,感兴趣的各位可以自行了解

深拷贝和浅拷贝的应用场景

浅拷贝适用于只需要复制一层对象引用的情况,比如克隆一个对象用于修改而不影响原始对象。

深拷贝适用于需要完全独立的对象副本的情况,比如避免修改原始对象或者将对象传递给其他函数时产生副作用。

需要根据具体的业务需求选择合适的拷贝方式,避免出现意料之外的问题。

总结

深拷贝和浅拷贝是前端开发中常见的概念,对于理解和应用它们的区别非常重要。浅拷贝只复制对象的一层引用,而深拷贝递归地复制对象及其子对象。在实际开发中,我们要根据具体的需求选择合适的拷贝方式,以确保代码的正确性和效率。