关于深拷贝和前拷贝的问题我觉得平时在项目中会经常用到,大家也比较熟悉;
下面从几个方面来说一下这个知识点吧;
1,基本的概念 ,原理
2,几种深浅拷贝的方法
3,实际的应用场景和实现
首先我们来谈谈 深拷贝和浅拷贝的概念;
基本类型的复制(都是在栈里的复制操作)
例如 var a=0; var b=a ; 这里的b拿a的值就是直接从栈里复制了一份出来 ,完全独立的副本;
这就是拷贝 ,无所谓深浅直说;
深拷贝 和浅拷贝是存在于引用类型上的 ;
例如 var a=[1,2,3,4,5] var b=a; 此时的a 保存是一个内存地址(堆里空间的指针) , b被a赋值也只是赋值了一个地址;
此时 这种情况就算是浅拷贝;
对一个对象拷贝的不够彻底 ,没有把里面的嵌套的 对象完全的拷贝下来 比如:
var a =[ {obj:"obj"},1,2,3] var b=[...a]; 现在b对于a 复制了 一层 ,数组里的对象里的地址a和b还是共用;
此时 这种情况就算是浅拷贝;
对于一个对象完全实现了深层次的拷贝,完完全全独立的实现了一个副本;
此时 这种情况就算是深拷贝;
再来说几种深浅拷贝的方法
前拷贝:
1,... 使用 扩展运算符可以使得 对象复制一层 ;
2,for循环实现一层拷贝;
例如
var a=[ 1,2,3,4,5]
var b=[],
for( var i=0; i<a.lenth;i++) {
b[i]=a[i]
}
3,数组的concat; 这也只是一种数组的前拷贝的方法
深拷贝的方法
1, json方法
var test ={
name:{
xing:{
first:'张',
second:'李'
},
ming:'老头'
},
age :40,
friend :['隔壁老王','宋经纪','同事']
}
var result = JSON.parse(JSON.stringify(test))
result.age = 30
result.name.xing.first = '往'
result.friend.push('fdagldf;ghad')
console.dir(test)
console.dir(result)
这种方法 只能复制不包含Function 和Date类型的 对象;这两种类型 会自己做转换;导致两个对象不一致;并且原型链也丢失了;
2,循环递归
var china = {
nation : '中国',
birthplaces:['北京','上海','广州'],
skincolr :'yellow',
friends:['sk','ls']
}
//深复制,要想达到深复制就需要用递归
function deepCopy(o,c){
var c = c || {}
for(var i in o){
if(typeof o[i] === 'object'){
//要考虑深复制问题了
if(o[i].constructor === Array){
//这是数组
c[i] =[]
}else{
//这是对象
c[i] = {}
}
deepCopy(o[i],c[i])
}else{
c[i] = o[i]
}
}
return c
}
var result = {name:'result'}
result = deepCopy(china,result)
console.dir(result)
这种实现比较彻底;实现一个独立的副本;
关于深浅拷贝的实际应用 大约就是jq的extend方法;
这是两个函数的合并方法;解释一下这个方法的用法:
1, $.extend( true, object1, object2 );
第2个对象已有的 key为基准 第1个对象合并到第2个对象; 就是说 两个对象都相同的key,那么以第2个对象为准 ,冲掉了第1个key对应的value; 所有的key都会被继承过来合并; 这就是深拷贝的实现;
2, $.extend( object1, object2 );
这种就是浅拷贝了; 和第一种用法 都一样,,,但是只有第一层的key会继承并合并;
这个api还有一种方法是实现插件机制的 暂不表