javascript中数据类型有8种,其中有7种原始类型:Boolean,Null,Undefined,Number,BigInt,String,Symbol
和 Object
。
我们通常也说基础类型和引用类型。
内存中,基础数据类型在栈中直接存储值,引用类型则是在堆中存储,然后把其在堆中的地址存储在栈里。
js浅拷贝,只是拷贝栈中的数据,js深拷贝,就是要完全拷贝,包括堆里数据。
举例说明:
let a = {index: 123, data: {name:'xiaochun'}}
let b = {};
for(let k in a){
b[k] = a[k]
}
上面的代码就是一个浅拷贝,a.data
和b.data
指向的还是同一个对象。如果修改b.data.name='chunge'
,那么a.data.name
也会变成chunge
。因为b只是拷贝了a这个对象存在栈中的地址,对象并没有被复制,堆中还是只有那一份数据。
b.data.name = 'chunge';
console.log(a.data.name); // chunge
console.log(b.data.name); // chunge
因此为了深入拷贝所有数据,我们需要不断递归深入去判断数据类型,如果是基础类型,直接拷贝值,如果是引用类型的,就要再深入进去判断拷贝,直到最后都是基础类型的。
引用类型的不仅仅是object,我们常见的还有数组array,object和数组里面还可能嵌套多级不同类型数据。
函数也是对象。函数有可能会在内部使用this。因此,函数需要注意this的重新绑定。
完整的深拷贝函数:
function deepClone(obj){
// 类型判断
var checkType = function(obj){
let val = Object.prototype.toString.call(obj).toLocaleLowerCase();
return val.substring(8,val.length-1);
}
// 函数拷贝,重新绑定this
function fnClone(fn, o){
return fn.bind(o);
}
// 数组拷贝
function arrayClone(arr){
let temp = [];
arr.forEach(v=>{
let type = checkType(v);
if( type === 'array'){
temp.push(arrayClone(v));
}else if(type === 'object'){
temp.push(objClone(v));
}else{
temp.push(v);
}
});
return temp;
}
// 对象拷贝
function objClone(data){
let temp = {};
for(let k in data){
let type = checkType(data[k]);
if(type === 'function'){
temp[k] = fnClone(data[k], temp);
}else if( type === 'array'){
temp[k] = arrayClone(data[k]);
}else if(type === 'object'){
temp[k] = objClone(data[k]);
}else{
temp[k] = data[k];
}
}
return temp;
}
// 获取参数类型
var type = checkType(obj);
switch (type) {
case 'array':
return arrayClone(obj);
case 'object':
return objClone(obj);
default:
return obj;
}
}
转载请注明带链来源:春语精椿