老生常谈js的拷贝问题,今天就简单来说说js的深拷贝和浅拷贝的问题,故事要从js对数据的存储开始说起。话说很久很久之前。。。。。。,js的存储分为堆(heap)和栈(stack)两种存储类型。
针对数据的存储方式,基本数据类型的数据存储在栈中,引用类型的数据存储在堆中,引用类型数据的堆的地址存储在栈中,所以说js的深浅拷贝只针对引用类型的数据,不针对基本数据类型的数据 ,其实深浅拷贝的区别是只要拷贝的是地址的都是浅拷贝,拷贝的是数据的都是深拷贝。
一、浅拷贝:当对象的属性都为非引用类型的数据的时候就可以使用浅拷贝,浅拷贝的方式主要有以下两种:
1、遍历对象的属性赋值给新对象
function shallowCopy(obj){
let copyObj={};
for(let key in obj){
if(obj.hasOwnProperty(key)){
copyObj[key] = obj[key];
}
}
return copyObj;
}
2、使用es6提供的Object.assign()方法,将后续的源对象的枚举属性赋值到目标对象中,第一个参数是一个目标对象,其他的都是源对象(如果属性中没有引用类型数据的话就是深拷贝了)
var shallowCopy = Object.assign(targetObj,srcObj1,srcObj2,....);
二、深拷贝:
1、JSON.parse(JSON.stringify()):转成json字符串之后再转为对象(前提是当前的源对象可以转为json字符串,undefined,function等不能使用该方法)
let targetObj = JSON.parse(JSON.stringify(srcObj))
2、使用递归逐层拷贝
function deepCopy(srcObj){
if(typeof srcObj !== 'object'){
return srcObj
}
let result = {};
for(let key in srcObj){
if(typeof srcObj[key] === 'object'){ //当前属性是引用类型属性
if(Array.isArray(srcObj[key])){
let arr = [];
let srcObjArr = srcObj[key];
for(var i=0;i<srcObjArr.length;i++){
arr.push(deepCopy(srcObjArr[i]))
}
result[key] = arr;
}else if(srcObj[key] === null || srcObj[key].constructor === RegExp){
result[key] = srcObj[key];
}else{
result[key] = deepCopy(srcObj[key])
}
}else{
result[key] = srcObj[key];
}
}
return result;
}