在上文中,已经提到了深浅拷贝的概念,以及常用的深浅拷贝的方法。这里进行一个简单的回顾:
- 改变了一个变量的值,其他变量也一并改变的原因是引用类型数据,栈中存放的是地址,两个变量用了同一份堆中的数据。
- 当数据为引用类型时,且想取消变量之间的关联,需要用到深浅拷贝。
- 当数据仅有一层时,利用...扩展运算符能很简单的实现数据的拷贝。
- 使用JSON.parse(JSON.stringify(obj));来进行深拷贝时,应注意对象中,不能存在Date、RegExp、Function类型的数据,不然会导致数据丢失。
可以发现,当我们使用JSON.parse(JSON.stringify(obj));来进行深拷贝时,对象中不能存在Date、RegExp、Function类型的数据。但实际应用中,不可避免的会出现类似情况。此时应该怎么处理呢?
这也是面试常问问题。
1、使用Lodash JS工具库
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。其中封装了 array、number、objects、string 等等类型的数据处理方法。
我们可以通过Lodash的cloneDeep(value)方法来实现对象的深拷贝。
官网地址:https://www.lodashjs.com/docs/lodash.cloneDeep
2、手写递归实现深拷贝
我的实现思路如下:
1、 通过递归实现深拷贝
2、 通过typeof 操作符判断数据类型(typeof 不是函数,是一元操作符)
3、 当数据类型为基本类型的时候和function,直接赋值
4、 当数据类型为Object,且为数组和对象的时候,进行递归
5、 利用for in 遍历数组和对象
6、 利用hasOwnProperty判断是否需要拷贝原型上的属性
7、 利用constructor判断数据类型。
8、 利用constructor返回对创建此对象的数组函数的引用的特性,通过new 实现对Date、RegExp的深拷贝。
function deepCopy(srouceData, onlyOwnProperty = true) {
let resultData;
if (typeof (srouceData) !== 'object') {
return srouceData;
} else {
if (srouceData.constructor === Array || srouceData.constructor === Object) {
resultData = new srouceData.constructor();
for (let key in srouceData) {
// 如果有需求,要过滤掉srouceData原型上的属性
if (onlyOwnProperty) {
if (Object.prototype.hasOwnProperty.call(srouceData, key)) {
resultData[key] = deep(srouceData[key])
}
} else {
resultData[key] = deep(srouceData[key])
}
}
} else {
return new srouceData.constructor(srouceData);
}
}
return resultData;
}
我们拿一个代码试试:
let srouceObj = {
a: 'a',
b: { b1: 'b1', bt: new Date('2020-11-1') },
c: [1, 2, 3],
d: new Date(),
e: new RegExp("[a-c]", "i"),
f: function a() {
alert('a')
}
}
let copyObj = this.deepCopy(srouceObj);
copyObj.b.b1 = 'b2';
copyObj.d.setFullYear(2016);
console.log(srouceObj)
// {
// a: "a",
// b: { b1: 'b1', bt: Sun Nov 01 2020 00:00:00 GMT+0800 (中国标准时间) },
// c: [1, 2, 3],
// d: Wed Feb 24 2021 12:13:53 GMT+0800 (中国标准时间),
// e: /[a-c]/i,
// f: f a()
//}
console.log(copyObj)
// {
// a: "a",
// b: { b1: 'b2', bt: Sun Nov 01 2020 00:00:00 GMT+0800 (中国标准时间) },
// c: [1, 2, 3],
// d: Wed Feb 24 2016 12:13:53 GMT+0800 (中国标准时间),
// e: /[a-c]/i,
// f: f a()
//}
拷贝成功。
网友评论