闲言碎语
我很早看过相关的大神的博客,但是之前知识掌握不太好,又加上记忆力不太好,所以就忘到十里之外了,今天刷题的时候看到一道问答题,让说说javaScript中的深复制(深度克隆),一刹那有些懵了,就各种搜索理解恶补一下。为了加深记忆和为自己做个笔记的驱动下,写个博客记录一下。
js中的数据类型,分为两大类:
基本数据类型:number、string、boolean、null、undefined (使用typeof进行检测判断,返回基本数据类型,但是typeof null =>‘object’)
引用数据类型:object(使用instanceof 进行检测,返回布尔值)
两者的区别:
1、存储方式不同:
基本数据类型是将变量名和值保存在栈内存中
引用数据类型是将变量名保存在栈内存中,将值保存在堆内存中,栈内存中有指向堆中(该值)的指针。
2、赋值方式不同:
基本数据类型是将变量名和值复制给另一个变量时,新变量将会在栈中开辟一个空间,和之前的变量/值也就无关了(忘恩。。哈哈)
引用数据类型是将当前变量指向堆内存的指针赋值给了新的变量,此时两个变量共享一个值,所以改变其中一个时另外一个也会发生变化(饮水思源。。嘿嘿)
敲黑板啦
所谓浅复制就是只是简单的赋值内容,当原内容变化是,新的内容随着变化,看起来很没有主见的样子哈(。。。),深复制就是不管原本的内容如何变化,我的内容就是不变,你变或不变,我的值就是这样不改不变。
浅复制
来个小栗子:
var arr1 = [9,3,[6,5],97,7];
var arr2 = arr1; //[9,3,[6,5],97,7]
arr1[0] = -1;
console.log(arr2); //[-1,3,[6,5],97,7]
可以看到arr2完全随着arr1的变化而变化,来个深复制
var color1 = [1,[2,3],3];
var color2 = [];
for(var i = 0;i < color1.length;i++){
color2[i] = color1[i];
}
console.log(color2); //[1, [2,3], 3]
color[0] = -1;
color[1][0] = 0;
console.log(color2); //[1, [0,3], 3]
上面的代码只能浅显的完成一层深复制,想要完全脱离color1的魔爪,还是不能实现。。。js数组中的slice()、concat()、Object.assign()、展开运算符(…)也是达到浅复制效果(请自行实现)。
深复制
这个呢稍微难理解一点,但是基础程度好的童鞋肯定会一笑而过的。有如下三种方式来实现。
1、通过递归的方式
在网上搜索你会发现,这中是出现率很高的一种方式,主要原理是对原对象进行递归检查,像上面例子数组中的数组一样,一旦发现子属性中还可以进行遍历,那么,就二话不说的再对其子属性进行遍历,直到只有自身为止(真是榨干榨净啊。。。)
代码实现:
function DeepCopy(obj){
var res;
if(Object.prototype.toString.call(obj)=='[object Array]'){ //判断传入参数是不是数组
res = []; //是数组的话定义为数组类型
for(var i = 0;i<obj.length;i++){
res[i] = DeepCopy(obj[i]); //对其子元素再进行递归遍历
}
}else if(Object.prototype.toString.call(obj) == '[object Object]'){ //判断传入参数是不是对象
res = {};
for(var key in obj){
res[key] = DeepCopy(obj[key]);
}
}else{
return obj;
}
return res;
}
使用这个函数再去重新复制 color2 就会有不一样的效果,其中Object.prototype.toString这个方法是干啥的呢??上面也说了使用typeof只能判断基本的类型,如果硬是用这个判断引用类型就会返回 “object”,所以呢可以通过Object.prototype.toString方法,判断某个对象属于哪种内置类型。
2、JSON.stringify与JSON.parse
var arrs = [9,3,[6,5],97,7];
function DeepCopy(obj){
var _str = JSON.stringify(obj); //转换为基本类型
var news = JSON.parse(_str); //再次转换,为json格式 再复制
return news;
}
var ac = DeepCopy(arrs);
console.log(arrs,ac);
arrs[0] = 0;
arrs[2][0] = 0;
console.log(arrs,ac);
3、extend
语法:$.extend( [deep ], target, object1 [, objectN ] )
deep:指示是否深度合并对象,,为true为深拷贝,为false,则为浅拷贝
target:Object类型 目标对象,其他对象的成员属性将被附加到该对象上
object1:可选。 Object类型 第一个被合并的对象
var a1 = [1,2,[3,4],5];
var a2 = $extend(true,[],a1);
console.log(a1,a2);
a1[0] = 0;
a1[2][0] = -1;
console.log(a1,a2);
官方的总结: 希望我写的这篇文章可以帮助你们,站在巨人的肩上可以看的更远,我写的之前也是看了好多关于这方面的知识。。有错或者写的不恰当的地方欢迎指出。
最后祝大家生活越来越美好,事业越来越顺利!