[JavaScript]JavaScript中的内存以及深浅拷贝的浅析

认识了解JS中的内存是很有必要的,他可以帮助我们理解垃圾回收(Garbage Collection)的概念、浅拷贝和深拷贝之间的区别。
所以我们有必要对JS中的内存空间有一个清晰的认识。

在JS中,每一个数据都需要一个内存空间。内存空间又被分为两种,栈内存(stock)与堆内存(heap)。

我们先来回顾一下七种数据类型:

  • 基本类型

    • Number
    • String
    • Symbol
    • Boolean
    • null
    • undefined
  • 复杂类型

    • Object

现在,我们分别来认识一下栈内存和堆内存:

基本数据类型与栈内存

在JavaScript中,基本数据类型的值是直接存放在栈内存中的。

var a = 1
var b = '1'
var c = a

c   //1
c = 2
a   //1

直接画图可以让我们有一个更直观的认识:

我们可以看到:

  • a 被赋值给了c
  • c 重新赋值2
  • a 的值不变

因为在基本数据类型中,他们的值在栈内存中是唯一的,所以就算是把一个变量A的值值赋值给另一个变量B,当这个变量B重新赋值的时候,A的值也不会改变,他们之间互不影响。

复杂类型与堆内存

在JavaScript中,复杂类型(也叫引用类型)的值是存放在堆内存中的。

在掘金上看到一篇文章,我觉得描述得很清晰明了,在此引用一下:

JavaScript不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。

如:

var a = {
    name: 'a'
}
var b = a
b.name = 'b'
a.name //'b'

当我们把b.name改为'b'的时候,其实我们操作的是和a的引用地址指向的同一个对象,但是因为a的引用地址没有改变,所以a.name也是'b'

现在我们明白了基本类型和栈内存、复杂类型和堆内存 之间的关系,我们就可以了解一下垃圾回收(Garbage Collection)了:

垃圾回收

来自MDN的解释:

JavaScript创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放。 后一个过程称为垃圾回收。

在MDN中还涉及了垃圾回收的算法之类的,但是目前我们不需要太深入,我们只需要了解一下垃圾回收的概念:简单地总结一下,就是如果一个对象没有被引用,他就是垃圾,他就会被回收。

如:


var a = {
    name: 'a'
}
var b = {
    name: 'b'
}
a = b
a   //{name: 'b'}

我们再上面这段代码中分别创建了a和b两个对象,他们分别有两个不同的引用地址,指向不同的堆内存对象。然后我们把b赋值给了a,这说明了a的引用地址现在也变成了b的引用地址,他们现在指向同一个堆内存对象。而a之前的引用地址所指向的堆内存对象,因为没有被任何对象引用,那么他就变成了垃圾,就会被回收:


深浅拷贝的概念

基本数据类型的拷贝

因为基本数据类型的值是直接存放在栈内存中,并且它的值的地址是唯一的,变量之间不能互相影响,所以涉及到基本数据类型的拷贝都是深拷贝。

//基本数据类型的拷贝
var a = 'a'
var b = a
b   //'a'
b = 'b'
b   //'b'
a   //'a'

复杂数据类型(引用类型)的拷贝

因为我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。所以复杂类型的浅拷贝实际上是对引用地址的拷贝:

var a = {
    name: 'a'
}
var b = a

b.name  //'a'

复杂类型的浅拷贝完成之后,被拷贝的对象a和拷贝出来的对象b分别拥有一个引用地址,指向同一个堆内存对象,所以,每当b或者a对对象的属性进行操作的同时,另一个对象的属性也会发生同样的改变,这就是浅拷贝。

基于复杂数据类型所进行的深拷贝,就是一旦拷贝成功,拷贝对象双方无论对属性进行怎样的修改,都不会影响到对方。

总结

  • 基本数据类型的值都存放在栈内存中
  • 复杂类型(引用类型)的值都存放在堆内存中,栈内存中存放的只是指向堆内存对象的引用地址
  • JavaScript创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放。 后一个过程称为垃圾回收
  • 深浅拷贝的概念
    • 基于基本数据类型的拷贝都是深拷贝,拷贝双方无论对各自的值做出什么修改,都不会影响到对方
    • 基于引用数据类型的拷贝分为浅拷贝和深拷贝,浅拷贝是当拷贝双方对各自的属性做出修改,对方的属性也会受到同样的影响;深拷贝就是一旦拷贝成功,拷贝对象双方无论对属性进行怎样的修改,都不会影响到对方。

掘金上的这篇文章帮我更深入地了解了这方面的内容,感谢这位作者。

posted @ 2018-08-21 17:35  小粒旬  阅读(164)  评论(0编辑  收藏  举报