数据拷贝在js中也是重要的一个知识点,数据拷贝分为简单数据类型的拷贝和复杂数据类型的拷贝,复杂数据类型又分为了深拷贝和浅拷贝.
简单数据类型
简单数据类型,string,num, boolean,null,undefine,symbol等这些简单的数据类型我们在复制的时候只需要'='赋值就可以实现拷贝操作.
复杂(引用)数据类型
我们知道在js中复杂数据在内存中是单独储存的,我们用的只是他的内存地址,所有我们直接=赋值的话,只是复制了他的内存地址,所以我们修改也会影响到之前的数据.
浅拷贝
浅拷贝就是拷贝引用数据类型的内存地址,我们常用的主要有以下几种方法.
- =赋值
- 数组的slice,contact等方法
- Object.assign()
- ...扩展运算法 以上几种方法都是对引用数据类型的浅拷贝,当我们修改是会影响到原数据.
深拷贝
深拷贝是拷贝数据,而不是内存地址,所以我们需要做一个特殊的处理,比如使用JSON对象方法,使用一些库的方法比如lodash,再或者自己封装一些方法.\
- JSON 我们可以通过JSON.stringify,JSON.parse先将数据转换为JSON格式,再转换回来
let array = [1, 2, 3];
let newArray = JSON.parse(JSON.stringify(array));
console.log(newArray, newArray === array); //[ 1, 2, 3 ] false
但是也有一些问题,有些数据不符合JSON格式的不能转换,比如undefined,symbol,function
let obj = {
name: 'zs',
age: 18,
eat: () => {
console.log('吃东西');
},
sex: undefined,
girlFriend: null,
id: Symbol('123')
};
let newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj);//{ name: 'zs', age: 18, girlFriend: null }
可以看到我们函数,undefined,symbol已经丢失了
- _.cloneDeep(value) lodash的深拷贝方法 _.cloneDeep(target) 返回结果值
let obj = {
name: 'zs',
age: 18,
eat: () => {
console.log('吃东西');
},
sex: undefined,
girlFriend: null,
id: Symbol('123')
};
var newObject = _.cloneDeep(obj);
console.log(newObject, obj === newObject);
- 自己封装方法
我们自己封装的时候有几个注意项
1判断null的存在
2.函数的复制
3.特殊对象,Reg,Date需要重新new一个
4.注意对象嵌套成环的情况.
function deepClone(origin, hashMap = new WeakMap()) {
// var a = undefined a == null // true
if (origin == undefined || typeof origin !== 'object') {
return origin;
}
if (origin instanceof Date) {
return new Date(origin);
}
if (origin instanceof RegExp) {
return new RegExp(origin);
}
const hashKey = hashMap.get(origin);
if (hashKey) return hashKey;
const target = new origin.constructor();
hashMap.set(origin, target);
// 剩下的就是[] 和 {} 函数静态不拷贝
for (const originKey in origin) {
if (origin.hasOwnProperty(originKey)) {
target[originKey] = deepClone(origin[originKey], hashMap);
}
}
return target;
}