浅拷贝
学深拷贝之前我们先了解一下浅拷贝
上面可以看到两个对象变成了一样的,由此可以得出浅拷贝只能拷贝一层。
深拷贝
1 JSON.parse(JSON.stringify())
这种深拷贝方式会有几个问题,让我们来看一下。
- 1 时间和正则的问题
使用这个方法执行后时间格式会变成字符串格式(正则同理)
- 2 丢失和类型
使用序列化之后会导致函数丢失,obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
自己实现一个深拷贝
/*
* 数据类型:基本数据类型,引用数据类型;
* 基本数据类型:String,null,undefined,Number,Boolean
* 引用数据类型:RegExp,Date,Array,object,Function
* */
function deepClone(value) {
//判断是否为null/undefined,因为在不是===的情况下 null=undefined if (value == undefined) return;
//判断是否是正则
if (value instanceof RegExp) return new RegExp(value);
//判断是否是时间格式
if (value instanceof Date) return new Date(value);
//判断是否是String,Number,Boolean,Function(因为函数不会进行拷贝,直接执行)
if (typeof value != 'object') return value;
// 能走到这里的只有数组和对象了
//value.constructor指向构造函数本身 Array/Object. new Array/new Object生成的就是[]/{}
let container = new value.constructor;
for (let key in value) {
container[key] = deepClone(value[key])
}
return container
}
let obj = {
a: [1, 2],
b: 500
};
let objCopy = deepClone(obj);
obj.a[0]=100;
console.log('我是obj', obj);
console.log('我是objCopy', objCopy);
上面基本实现了一个深拷贝,但是在这个方法中还存在些问题。如果我传入这样一个对象那么就会出现爆栈的现象。
let b={};
let a = {b:b};
b.a=a;
let copy = deepClone(a);
console.log(copy);
浏览器报错:
这个方法显然不是很友好,那么我们使用Map和Set函数来优化一下,如果在Map中能找到直接使用Map中的即可;
完整代码:
/*
* 数据类型:基本数据类型,引用数据类型;
* 基本数据类型:String,null,undefined,Number,Boolean
* 引用数据类型:RegExp,Date,Array,object,Function
* */
//传入map
function deepClone(value, hash = new Map()) {
//判断是否为null/undefined,因为在不是===的情况下 null=undefined if (value == undefined) return;
//判断是否是正则
if (value instanceof RegExp) return new RegExp(value);
//判断是否是时间格式
if (value instanceof Date) return new Date(value);
//判断是否是String,Number,Boolean,Function(因为函数不会进行拷贝,直接执行)
if (typeof value != 'object') return value;
//进来先判断是不是在map中,如果存在直接获取,就不需要再执行下面的deepClone函数进行递归为浏览器开辟无数个新的内存了。
if (hash.get(value)) {
return value;
}
// 能走到这里的只有数组和对象了
//value.constructor指向构造函数本身 Array/Object. new Array/new Object生成的就是[]/{}
let container = new value.constructor;
//每次进来向map函数中存值
hash.set(value, container)
for (let key in value) {
container[key] = deepClone(value[key], hash)
}
return container
}
let b = {};
let a = {b: b};
b.a = a;
let copy = deepClone(a);
console.log(copy);
输出结果