JS如何实现深拷贝
背景知识:
基本数据类型:undefined、null、number、boolean、string、symbol
引用数据类型:object(数组、函数等都属于引用数据类型)
常用的实现深拷贝的方法:
1、使用JSON.stringify
const arr = [
{ a: new Date(), aa: new RegExp('\\w+'), aaa: function() { console.log('aaa function') } },
{ b: 'qwe' },
{ c: [null, undefined] },
{ d: [{ da: 1, db: { dba: 123 }}] }
]
const copyArr = JSON.parse(JSON.stringify(arr))
console.log(copyArr)
不足:
1、日期类型的数据会直接变成字符串的形式,而不是对象的形式
2、正则类型的数据会变成空对象{}
3、函数会丢失
优点:能够满足大部分的业务需求、代码量少
2、自定义实现深拷贝函数
相比较于JSON.stringify的方式增加了日期和正则类型的数据的拷贝
function clone(obj) {
// 当null NaN undefined number string等基本数据类型时直接返回
if (obj === null || typeof obj !== 'object') {
return obj
}
// Date类型
if (obj instanceof Date) {
const copy = new Date()
copy.setTime(obj.getTime())
return copy
}
// 正则类型类型
if (obj instanceof RegExp) {
const Constructor = obj.constructor
return new Constructor(obj)
}
// 如果是数组等引用数据类型
if (obj instanceof Array || obj instanceof Object) {
const copyObj = Array.isArray(obj) ? [] : {}
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copyObj[key] = clone(obj[key])
}
}
return copyObj
}
}
不足:没有实现函数的复制
3、使用lodash.js中的cloneDeep函数
具体可以见官网的示例:lodash.js cloneDeep函数
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<script>
var objects = [
{ a: new Date(), aa: new RegExp('\\w+'), aaa: function() { console.log('aaa function') } },
{ b: 'qwe' },
{ c: [null, undefined] },
{ d: [{ da: 1, db: { dba: 123 }}] }
]
var deep = _.cloneDeep(objects);
console.log(deep);
为什么会有深拷贝与浅拷贝?
引用数据类型的数据相对于基本数据类型的数据而言,由于其存储的方式不一样,因而有深浅拷贝之分。
基本数据类型的值是直接存放在栈内存当中的,引用数据类型在栈内存中存放的是该对象在堆内存中的起始地址。如对象c在栈内存中的值就是c[0]在堆中的地址。
因此深浅拷贝都是相对于引用数据类型来说的,浅拷贝是只复制了对象的地址,深拷贝是重新在内存中开辟一块地址用于存储值。图中的var d = c就属于浅拷贝,对象c与d的指向的地址是一样的。