前言
浅拷贝与深拷贝在工作中经常会遇到,而且面试也是一个考点。在此自行总结记录下吧。
预备知识
一、数据类型
JavaScript数据类型有两种:『基本数据类型』和『引用数据类型』。
基本数据类型: String, Number, Boolean, Null, Undefined,Symbol
引用数据类型: 对象、数组、函数、正则表达式等(但其实除了基本数据类型以外,其他都是对象)
二、栈和堆
示意图如上
基本数据类型的特点:直接存储在栈(stack)中的数据
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
浅拷贝与深拷贝
浅拷贝与深拷贝主要是针对引用数据类型(对象、数组、函数等)的。区别如下图
浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值
如果属性是引用类型,拷贝的就是栈内存地址 ,由于拷贝者得到的是栈内存放的地址,因此当拷贝者的属性值发生改变时(堆内存里存放的值发生变化),原数据也会发生变化(原数据与新数据是联动的)。
深拷贝
深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
浅拷贝与深拷贝的实现方法
浅拷贝
PS:当拷贝对象只有一层的时候,效果和深拷贝一样了
- Object.assign(target, source)
该方法将所有可枚举的自有属性从一个或多个源对象复制到目标对象,返回修改后的对象。(没有的属性则添加,已有的属性则覆盖,目标数组会发生改变) - Array.prototype.concat(arr2)
此方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。 - Array.prototype.slice(begin,end)
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。 - 扩展运算符 …
扩展运算符可以将数组或者对象转为用逗号分隔的参数序列(每次只能展开一层)
let ary1 = [1,2,3]
let arr2 = [3,4,5]
...ary1 // 1,2,3
// log打印可以同时打印多个,用逗号分开,而扩展运算符刚好有逗号
console.log(...ary1) // 1 2 3
let arr3 = [...ary1, ...ary2]
console.log(arr3) // 1,2,3,3,4,5
深拷贝
-
JSON.parse && JSON.stringify()
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。不过需要注意的是,这种方法虽然可以实现数组或对象深拷贝,但不能处理函数 -
函数库lodash
直接调用 -
手撕(面试可能考)
用到了判断类型以及递归方法,不是自己写的,之后刷题的时候应该会遇到
浅拷贝与赋值的区别
赋值:基本数据类型和引用数据类型都会影响(联动)
浅拷贝:基本数据类型不会影响,引用数据类型会影响(联动)