关于JavaScript的深拷贝和浅拷贝

143 阅读2分钟

定义

浅拷贝是在在拷贝过程中,遍历时那是将新值指向旧值的存储地址。

而深拷贝,则是完全开辟新的内存地址,再将旧值完全拷贝过来

区别

浅拷贝的新值和旧值的地址指向是相同的。所以新值,旧值也会跟着改变,修改旧值也会改变新值。

而深拷贝的新值是放在一个全新的存储空间中,已经和旧值断了联系,修改哪一个,也不会改变另外一个。

补充

  • 默认情况下基本数据类型(number,string,null,undefined,boolean)都是深拷贝。
  • 默认情况下引用类型(object,array)都是浅拷贝。
  • 基本数据类型,存放在栈内存中。引用数据类型,存放在堆内存中。
  • 深拷贝和浅拷贝只是针对的是引用数据类型,如数组,对象等。基本数据类型没有深拷贝和浅拷贝之说,只是简单的赋值操作。

解构中的拷贝

解构赋值到底是深拷贝还是浅拷贝?

如果所解构的原对象是一维数组或对象,其本质就是对基本数据类型进行等号赋值,是深拷贝

如果是多维数组或对象,其本质就是对引用类型数据进项等号赋值,是浅拷贝

严格的来说:解构赋值是浅拷贝,因为它确实不能对多维数组或对象达到深拷贝的作用。

常用的深拷贝方法

在处理业务时,为了避免当修改一个变量的时候另一个变量也随着改变,所以常常会用到深拷贝。

最常用的方法是:

 let b = JSON.parse(JSON.stringify(a));

这样就将a深拷贝给了b,其中的原理是:

JSON.stringify()⽅法⽤于将JavaScript 值转换为 JSON 字符串

JSON.parse()方法将JSON格式字符串转换为js对象。解析前要保证数据是标准的JSON格式,否则会解析出错。

但是这个方法有着很大的弊端

  1. 耗性能
  2. 需要拷贝的对象中不能有JavaScript的关键字,否则会丢失。如一个对象中含有属性{foo:function(){}},再用此方法拷贝之后,拷贝后的对象会丢失掉foo这个属性

面试题:手写深拷贝实例

代码如下

 function deepClone(source) {
     //参数source为需要拷贝的对象或数组
     //根据source的类型给予不同的容器
     const targetObj = source.constructor === Array ? [] : {};
     for (let keys in source) {
         if (source.hasOwnProperty(keys)) { //判断这个属性是不是source独有的,这行代码可以根据情况决定是否使用
             if (source[keys] && typeof source[keys] === 'object') {
                 targetObj[keys] = deepClone(source[keys]) //递归
             }else {
                 targetObj[keys] = source[keys]
             }
         }
     }
     return targetObj;
 }