一、采用JSON字符串实现深拷贝
let obj = {name:'zhangsan',age:13,hobby:['basketball','pingpang','dance'],score:{a:1,b:2}}// 使用JSON进行深拷贝let res = JSON.parse( JSON.stringify(obj))// 测试代码res.score.a = 12console.log(res,obj)
缺点:
- 对象方法不会拷贝
- 数组中的undefined会变为null,对象上的undefined不会拷贝
- symbol不会拷贝
- 正则变成了空对象
- Infinite会变为null
一些类型的对象会被转换为字符串
let obj = {c:new Date()}// 使用JSON进行深拷贝let res = JSON.parse( JSON.stringify(obj))console.log(res,obj)// res: c: '2022-02-23T03:15:43.266Z'// obj: c: Wed Feb 23 2022 11:15:43 GMT+0800 (中国标准时间)
循环引用会报错
obj.score = obj// 使用JSON进行深拷贝let res = JSON.parse( JSON.stringify(obj))

不能转换BigInt类型
二、递归实现
封装一个函数,解决json字符串深拷贝产生的问题 处理循环调用问题,可以使用:数组或set保存已经处理过的数据,解决循环引用的问题(本案例使用数组)
// 封装一个获取数据类型的函数function toType(data) {return Object.prototype.toString.call(data).slice(8, -1)}// 使用递归方式处理深拷贝 ,参数1:要拷贝的数据,参数2:解决循环引用(不用传参)const deepClone = function (target, done = []) {// 处理一些特殊数据类型if (target == null) return target // 如果是null或undefined,如果是就返回该值// 获取数据的类型,以及其构造器(避免后面频繁用到)let type = toType(target)let col = target.constructorif (type === "RegExp" || type === "date") return new col(target) // 如果是正则或date返回新的实例if (type === "Error") return new col(target.message) // 如果是ERROR实例,返回该信息的实例if (type === 'Function') return function () { // 如果是函数,返回一个新的函数包裹该函数target.apply(this, arguments)}if (type !== "Array" && type !== "Object") return target // 不是对象和数组(除以上的其他基本数据类型),则返回该数据// 解决循环引用问题if (done.includes(target)) return target // 如果已经处理过该数据,就直接返回该数据(不处理)done.push(target) // 没有处理过的数据就放入该数组中,在递归时将done做为第二个参数传入// 数组或者对象,遍历递归let res = new col() // 创建一个新的数组或对象,用于存储拷贝后的数据Object.keys(target).forEach(key => { // 遍历对象或者数组res[key] = deepClone(target[key], done) //递归,第二个参数处理循环引用问题})return res}
