赋值、浅拷贝和深拷贝

赋值、浅拷贝和深拷贝

在普通数据类型中,将变量a的值赋值给变量b后,变量a、b是两个值相同但是独立的个体,他们值改变不会影响到对方。因为普通数据类型的值是存放在栈区域,执行b=a后,新开辟一个地址给b,然后把a的值复制到这个地址中,a本身没有受到任何影响。

引用数据类型中就没有普通数据类型那么简单。
1. 赋值
引用数据类型的值存放在堆区域,它变量名称指向的是值所在堆区域的地址。
当把对象obj赋值给obj2时,赋值的是地址,obj2指向的堆区域内容和obj是同一个。因此当我们修改obj2中的a属性值时,obj也会跟着改变。

	var obj = { a: 10 }
	obj2 = obj
	obj2.a = 20
	console.log(obj) //结果为{a: 20}

在这里插入图片描述

2. 浅拷贝
浅拷贝就是比赋值多了一层,把对象的值复制一份赋给一个新变量,当对象内的属性值全是基础数据类型时,在新变量上改变属性值,原来的对象不会受到影响。
浅拷贝的实现方法:
(1) Object.assign()
(2) 展开运算符 {…obj}

	var obj = {
		name: 'rose',
		age: 12
	}
	var newObj = Object.assign({},obj) //或 newObj = {...obj}
	newObj.age = 14
	console.log(obj.age) //12
	console.log(newObj.age) //14

但当对象内存在属性值为引用数据类型时,改变该对象内的引用数据类型的值,原来的对象也会跟着改变。可见,浅拷贝只能拷贝第一层。当对象中的属性值为对象时,拷贝的也是地址。

	var obj = {
		name: 'rose',
		age: 12,
		hobby: {dance: true}
	}
	var newObj = Object.assign({},obj) //或 newObj = {...obj}
	newObj.age = 14
	newObj.hobby.dance = false
	console.log(obj.age) //12
	console.log(newObj.age) //14
	console.log(newObj.hobby.dance) //false
	console.log(obj.hobby.dance) //false

3. 深拷贝
深拷贝是把数据的每一层都拷贝。在新变量上改变值时不会影响到原来的。
深拷贝的实现方式:JSON.parse(JSON.stringify(obj))
该方法的缺点是会忽略undefined和symbol,不能解决循环引用的对象。

	var obj = {
		name: 'rose',
		age: 12,
		hobby: {dance: true},
		sex: Symbol('sex'),
		say: function(){}
	}
	var newObj = JSON.parse(JSON.stringify(obj))
	newObj.age = 14
	newObj.hobby.dance = false
	console.log(obj.age) //12
	console.log(obj.hobby.dance) //true
	console.log(newObj) //{name:'rose', age: 14, hobby:{dance: false}}

JSON.parse(JSON.stringify(obj))不能解决循环引用的对象,下边的代码执行会报错。

	let obj = {
	  a: 10,
	  b: {
	    c: 20,
	    d: 30,
	  },
	}
	obj.c = obj.b
	obj.e = obj.a
	obj.b.c = obj.c
	obj.b.d = obj.b
	obj.b.e = obj.b.c
	let newObj = JSON.parse(JSON.stringify(obj))
	console.log(newObj)

版权声明:本文为weixin_44825338原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。