使用const data = JSON.parse(JSON.stringify(x))
完成的深拷贝
可解决大部分情况下深拷贝需求,但不支持Date、正则、undefined、函数等数据,且不支持引用。
所以此时需要一个更完备的深拷贝方法。
先上最终代码
const cache = new Map()
function deepClone(obj){
if(typeof obj !== 'object' || obj === null) return obj;
if(cache.get(obj)){
return cache.get(obj)
}
let result = {}
if(obj instanceof Function){ // 不能100%拷贝
if(obj.prototype){
result = function(){
return obj.apply(this,arguments)
}
}else{
result = (...args) => a.call(undefined, ...args)
}
}
if(obj instanceof Array){
result = []
}
if(obj instanceof Date){
result = new Date(obj - 0)
}
if(obj instanceof RegExp){
result = new RegExp(obj.source, obj.flags)
}
cache.set(obj, result)
for(let key in obj){
result[key] = deepClone(obj[key])
}
return result
}
// 测试数据
const obj1 = {
number:1, bool:false, str: 'hi', empty1: undefined, empty2: null,
array: [
{name: 'hy', age: 18},
{name: 'jacky', age: 19}
],
date: new Date(2000,0,1,20,30,0),
regex: /\.(j|t)sx/i,
obj: { name:'frank', age: 18},
f1: (a, b) => a + b,
f2: function(a, b) { return a + b }
}
obj1.self = obj1
const obj2 = deepClone(obj1)
obj1.array[0] = 'xxx'
基本实现
// 创建函数
function deepClone(obj){
// 创建返回值变量
let result = {}
return result
}
function deepClone(obj){
/* 其他代码 */
//传参不为对象 直接return
if(typeof obj !== 'object' || obj === null) return obj;
/* 其他代码 */
}
function deepClone(obj){
/* 其他代码 */
// 传参为函数
if(obj instanceof Function){ // 不能100%拷贝
//普通函数
if(obj.prototype){
result = function(){
return obj.apply(this,arguments)
}
}else{
//箭头函数
result = (...args) => a.call(undefined, ...args)
}
}
/* 其他代码 */
}
function deepClone(obj){
/* 其他代码 */
// 传参为数组
if(obj instanceof Array){
result = []
}
/* 其他代码 */
}
function deepClone(obj){
/* 其他代码 */
// 传参为日期
if(obj instanceof Date){
// obj为日期时,则格式如 -> Sun Jun 19 2022 20:03:03 GMT+0800 (中国标准时间)
// obj - 0 则得到此时间戳 -> 1655640152585
// 再将此时间戳赋予到new Date中
result = new Date(obj - 0)
}
/* 其他代码 */
}
function deepClone(obj){
/* 其他代码 */
// 传参为正则
if(obj instanceof RegExp){
result = new RegExp(obj.source, obj.flags)
}
/* 其他代码 */
}
function deepClone(obj){
/* 其他代码 */
// 基本赋值
for(let key in obj){
// 有些属性是继承,有些属性是自身,我们只遍历自身属性
if(obj.hasOwnProperty(key)){
// 直接赋值是不行的,因为obj[key]也有可能是对象,直接赋值就变成了浅拷贝
// result[key] = obj[key]
// 正确写法,赋值前调用深拷贝方法,如果是普通类型则不变,如果为对象类型则进行深拷贝。
result[key] = deepClone(obj[key])
}
}
/* 其他代码 */
}
基本完成
function deepClone(obj){
if(typeof obj !== 'object' || obj === null) return obj;
let result = {}
if(obj instanceof Function){ // 不能100%拷贝
if(obj.prototype){
result = function(){
return obj.apply(this,arguments)
}
}else{
result = (...args) => a.call(undefined, ...args)
}
}
if(obj instanceof Array){
result = []
}
if(obj instanceof Date){
result = new Date(obj - 0)
}
if(obj instanceof RegExp){
result = new RegExp(obj.source, obj.flags)
}
for(let key in obj){
if(obj.hasOwnProperty(key)){
result[key] = deepClone(obj[key])
}
}
return result
}
// 测试数据
const obj1 = {
number:1, bool:false, str: 'hi', empty1: undefined, empty2: null,
array: [
{name: 'frank', age: 18},
{name: 'jacky', age: 19}
],
date: new Date(2000,0,1,20,30,0),
regex: /\.(j|t)sx/i,
obj: { name:'frank', age: 18},
f1: (a, b) => a + b,
f2: function(a, b) { return a + b }
}
const obj2 = deepClone(obj1)
obj1.number = 2
解决环状问题
之前已经可以满足普通的深拷贝需要了,但此时还有个问题
那就是在深拷贝前,如果变量obj1的self等于自身,也就是说先做了obj1.self = obj1
的操作。
之后我们再运行const obj2 = deepClone(obj1)
这行代码,则会报错..
如何解决...
// 第一步
const cache = new Map()
function deepClone(obj){
/* 其他代码 */
// 第二步
if(cache.get(obj)){
return cache.get(obj)
}
/* 其他代码 */
// 第三步
cache.set(a, result)
for(let key in obj){
if(obj.hasOwnProperty(key)){
result[key] = deepClone(obj[key])
}
}
/* 其他代码 */
}
此时再运行obj1.self = obj1
+ const obj2 = deepClone(obj1)
,就不会再报错啦