前言
js数据类型分为基本类型和引用类型两种
基本类型有:string,number,boolean,null,undefined,symbol
引用类型有:Function,Array,Object
一、赋值与浅拷贝
1.赋值
var obj1={
name:'张三',
age:18,
class:['一班']
}
var obj2=obj1//进行了赋值的操作
obj2.name='哈哈'
obj2.class[0]='二班'
console.log(obj1,1111)
console.log(obj2,2222)
打印结果如下:
结论:从例子的可以看出赋值后的对象obj2改变,原对象obj1的值也改变.这是因为赋值后的对象obj2赋值的是原对象obj1的栈内存地址,他们指向的是同一个堆内存数据,所以对赋值后的对象obj2对数据进行操作会改变公共的堆内存中的数据,所以原对象的值也改变了。
2.浅拷贝
var obj1={
name:'张三',
age:18,
class:['一班']
}
function qianCopy(obj){
var obj2={}
for(var attr in obj){//循环对象的所有属性值
if(obj.hasOwnProperty(attr)){
obj2[attr]=obj1[attr]
}
}
return obj2
}
var obj3=qianCopy(obj1)
obj3.name='傻逼'
obj3.class[0]='九班'
console.log(obj1,1111)
console.log(obj3,3333)
打印结果如下:
结论:从结果可以看出obj3改变了基本类型的值name,并没有使原对象obj1的name改变,obj3改变了引用类型的值,导致原对象的值也改变了
赋值和浅拷贝的区别总结:
赋值:就是对原对象的栈内存地址进行复制,但是他们的堆内存数据还是共享的。
浅拷贝:是对原对象的属性值进行精准复制,如果原对象的属性值是基本类型,那就是值的引用,所以浅拷贝后修改基本类型不会修改到原对象的,如果原对象属性值是引用类型,那么就是对引用类型属性值的栈内存的复制,所以修改引用类型属性值的时候会修改到原对象。
因此一般对无引用类型的属性的兑现拷贝的时候使用浅拷贝就行,对复杂对象包含引用类型属性的时候使用深拷贝
二、浅拷贝的实现方式
1.对象浅拷贝Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
代码如下(示例):
var obj1={
name:'张三',
age:18,
class:['一班']
}
let obj2=Object.assign({},obj1)
obj2.class[0]='五班'
obj2.age=19
console.log(obj1,111)
console.log(obj2,222)
打印结果如下:
可以看出原对象obj1属性中不包含引用类型的时候等价于深拷贝,因为不包含引用类型的时候是对属性值的拷贝也就是值引用,所以对拷贝的对象改变不会影响到原对象,也就等价于深拷贝
2.数组的浅拷贝…Array.prototype.slice()与Array.prototype.concat()
代码如下(示例):
var obj1 = ['张三', 18,{ class: '一班' }]
let obj2=obj1.slice()
obj2[0]='哈哈'
obj2[2].class='五班'
console.log(obj1,111)
console.log(obj2,222)
打印:
var obj1 = ['张三', 18,{ class: '一班' }]
let obj2=obj1.concat()
obj2[0]='哈哈'
obj2[2].class='五班'
console.log(obj1,111)
console.log(obj2,222)
concat方法结果一样。
3.解构
let aa = {
age: 18,
name: 'aaa',
address: {
city: 'shanghai'
}
}
let bb = {...aa};
bb.address.city = 'shenzhen';
console.log(aa.address.city); // shenzhen
三、深拷贝的实现方法
1.JSON.parse(JSON.stringify())
var arr = ['jack',25,{hobby:'tennise'}];
let arr1 = JSON.parse(JSON.stringify(arr))
arr1[2].hobby='rose'
arr1[0]='rose'
console.log( arr[2].hobby) //tennise
console.log( arr[0]) //jack
缺点:当对象里面有函数的话,深拷贝后,函数会消失
2.手写递归函数实现深拷贝
var obj = { //原数据,包含字符串、对象、函数、数组等不同的类型
name:"test",
main:{
a:1,
b:2
},
fn:function(){
},
friends:[1,2,3,[22,33]]
}
function copy(obj){
let newobj = null;
if(typeof(obj) == 'object' && obj !== null){
newobj = obj instanceof Array? [] : {};
for(var i in obj){
newobj[i] = copy(obj[i])
}
}else{
newobj = obj
}
return newobj; //函数必须有返回值,否则结构为undefined
}
var obj2 = copy(obj)
obj2.name = '修改成功'
obj2.main.a = 100
console.log(obj,1111)
console.log(obj2,2222)
打印结果:
总结
1.赋值时不论基本数据类型还是引用数据类型,当通过赋值得到的新对象改变时,原对象数据都会同步改变。
2.浅拷贝时基本数据类型并不用担心原对象改变,引用类型 才会改变原对象。
3.JSON.parse(JSON.stringify())深拷贝时,注意函数会消失。