JS赋值、浅拷贝、深拷贝的区别

发布时间 2023-12-01 16:56:48作者: 沐夏52Hz

在说明它们的区别之前,首先需要了解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要设个空对象或者数组,否则就相当于直接赋值而不是浅拷贝。