JS赋值、浅拷贝、深拷贝的区别
在说明它们的区别之前,首先需要了解JS的数据类型和它们的存放位置。
数据类型
基本数据类型:String、Number、Boolean、Undefined、Null、Symbol(es6)、BigInt(es6)
引用数据类型:Object
存放位置
基本数据类型是存放在栈中的数据段,直接存储的就是值本体。
引用数据类型是存放在堆中的对象,因此栈中会生成一个对应的指针,也就是“地址”,指针指向的是堆中的具体位置。
区别
了解到以上内容后,就可以正式区分三种不同的方法啦。
赋值
给引用类型赋值的时候,赋值的是对象在栈中的指针地址,而不是在堆中的值本身,所以两者指向的是同一存储空间,当其一值发生变化的时候,两者都会改变。
let obj1 = { a: '1', b: '2', c: { d: '3' } } let obj11 = obj1 obj11.a = 'a' obj11.c.d = 'd' console.log('obj1', obj1) console.log('obj11', obj11) // obj1 { a: 'a', b: '2', c: { d: 'd' } } // obj11 { a: 'a', b: '2', c: { d: 'd' } }
浅拷贝
浅拷贝区别于赋值的地方在于,它在堆中重新创建了新的内存空间,把原对象的值复制了一份赋给了新变量。所以当对象中的属性是基本类型时,两个对象互不影响对方;而当对象中的属性是引用类型时,因为共享了同一空间,会互相影响。
let obj2 = { a: '1', b: '2', c: { d: '3' } } let obj22 = Object.assign({},obj2) obj22.a = 'a' obj22.c.d = 'd' console.log('obj2', obj2) console.log('obj22', obj22) // obj2 { a: '1', b: '2', c: { d: 'd' } } // obj22 { a: 'a', b: '2', c: { d: 'd' } }
深拷贝
深拷贝的处理是最独立的,它在堆中完全开辟了新的内存地址,并将原对象完全复制过来。因此在修改深拷贝过的新对象时,二者完全独立、互不影响。
let obj3 = { a: '1', b: '2', c: { d: '3' } } let obj33 = JSON.parse(JSON.stringify(obj3)) obj33.a = 'a' obj33.c.d = 'd' console.log('obj3', obj3) console.log('obj33', obj33) // obj3 { a: '1', b: '2', c: { d: '3' } } // obj33 { a: 'a', b: '2', c: { d: 'd' } }
注意
1. 以上区别只针对引用数据类型。
基本类型就是直接把栈中存放的值本体给了出去,栈内存会开辟一个新的变量名,前后两个变量互不影响。
2. 浅拷贝使用Object.assign(target,sources) 的时候,target要设个空对象或者数组,否则就相当于直接赋值而不是浅拷贝。