说到深浅拷贝,那肯定要提到JavaScript的数据类型,先从数据类型说起。
JavaScript有两种数据类型:基础数据类型和引用数据类型。
基础数据类型又有以下几种: null 、undefined、number、string、Boolean;
引用数据类型包括:object、array、function;
基础数据类型都是按值访问的,我们可以直接操作保存在变量中的实际的值。而引用类型如Array,我们不能直接操作对象的堆内存空间,引用类型的值都是按引用访问的,即保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。
下面要说正事啦!!
深拷贝与浅拷贝的区别:
浅拷贝只复制指向走个对象的指针,而不是复制对象本身,新旧对象共享一块内存;
深拷贝复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。
基础数据类型的数据不存在浅拷贝,只有引用数据类型存在深浅拷贝的区别,深拷贝就是一直拷贝到基础数据类型为止;
下面再说几种常见的深拷贝的实现方式:
1、转成JSON
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
但这种方法的缺陷是会破坏原型链,并且无法拷贝属性值为function的属性。
2、递归
采用递归的方法去复制拷贝对象
3、jquery有提供一个$.extend可以用来做深拷贝。
4、手动复制。
//检测数据类型
function checkType(value) {
//推荐一个好用的数据类型判断的方法:Object.prototype.toString.call(value)
return Object.prototype.toString.call(value).slice(8,-1);
}
//实现克隆
function clone(val) {
let result,valType = checkType(val);
if(valType === 'Object') {
result = {};
} else if (valType === 'Array') {
result = [];
} else {
return val;
}
//遍历
for(let item in val) {
let temp = val[item]
//继续判断每一项是否为数组或者对象
if(checkType(temp) === 'Object' || checkType(temp) === 'Array') {
result[item] = clone(temp)
} else {
result[item] = temp
}
}
return result
}
综述就是:在复制非基础类型数据的时候,一直拷贝到基础数据类型的复制就算深拷贝!
注释:toString为Object的原型方法,而Array ,function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串.....),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。