浅拷贝
:拷贝这个词顾名思义 就是复制 但是在程序中复制却有很大差距,数据类型有基本数据类型和引用数据类型 。基本数据的拷贝就是拷贝的值,而引用数据类型复制的值其实复制的是地址,正是因为这样所以我们一般都是创建一个新的空对象 然后遍历旧对象。但是如果旧对象的属性是引用数据类型的话,遍历时其实拷贝的是地址。就要在递归调用,也就是所谓的深拷贝,本篇文章不介绍了,可以去我其他文章观看。
1.手写浅拷贝
var obj={
name:"xixi",
age:"age"
}
function clone(obj){
var newobj={}
for(var key in obj){
if(obj.hasOwnProperty(key)){
newobj[key]=obj[key]
}
}
return newobj
}
var obj2=clone(obj)
console.log(obj,obj2)
console.log(obj==obj2)
结果如下图
2.Object.assign()
Object.assign(target,source) 方法可以把任意多个的源对象自身的可枚举对象属性拷贝给目标对象然后返回目标对象 但需要注意的是Object.assign() 进行的到底是深拷贝还是浅拷贝呢 Object.assign()其实 是浅拷贝 不能算深拷贝
var obj={
name:"xixi",
age:"12",
skill:{
play:["电脑游戏","排球"],
read:"book"
},
hobbies:["篮球","足球"]
}
var newobj=Object.assign({},obj)
newobj.hobbies.pop()
newobj.skill={}
console.log(newobj,obj)
遍历时newobj.hobbies 其实和obj.hobbies 拷贝的是地址 两者指向的是同一个对象 newobj.skill={} 为什么这边两个不一样呢 因为newobj.skill指向了一个对象 地址发生改变了,但是之前的还是没有发生变化。
看变化
var obj={
name:"xixi",
age:"12",
skill:{
play:["电脑游戏","排球"],
read:"book"
},
hobbies:["篮球","足球"]
}
var newobj=Object.assign({},obj)
newobj.skill.read="news"
newobj.skill.play=["lol"]
// 你会发现原来的对象里的属性read 被改变了
console.log(newobj,obj)
</script>
3.Array.prototype.concat()
concat() 是数组里的一个内置方法,用来合并两个数组或者多个数组,其实他还具有打散数组的功能。这里我们不深究,主要 讨论的是浅拷贝一个
数组。 这个方法返回一个新数组,而不是修改原数组。
你会想不应该互不干扰? 但是在拷贝的时候 拷贝newarr[4]的地址 所以两者指的还是同一个对象。
var arr=[1,2,3,4,{name:"xixi"}]
var newarr=Array.prototype.concat([],arr)
newarr[4].name="hh"
console.log(newarr,arr)
结果如下图
你会发现新旧数组都发生改变了,因为两个数组对象的地址不一样互不干扰。 看下面例子。
var arr=[1,2,3,4,{name:"xixi"}]
var newarr=Array.prototype.concat([],arr)
newarr.pop()
console.log(newarr,arr)
4.Array.prototype.slice()
slice() 也是数组中的一个内置方法,该方法会返回一个新对象。slice() 不会改变原数组
var arr=[[1,2],3,4,{name:"xixi"}]
var newarr=arr.slice()
newarr[0]=[1,2,3]
console.log(newarr,arr)
这里newarr[0]拷贝的时候 地址是一样的指向同一个对象,但是新数组→了新的对象两者还是互不干扰的。
改变二级属性时,发现又不同了
var arr=[[1,2],3,4,{name:"xixi"}]
var newarr=arr.slice()
newarr[arr.length-1].name="hh"
console.log(newarr,arr)
他和前面的concat()表现得浅拷贝一摸一样。