zoukankan      html  css  js  c++  java
  • [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创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放。 后一个过程称为垃圾回收
    • 深浅拷贝的概念
      • 基于基本数据类型的拷贝都是深拷贝,拷贝双方无论对各自的值做出什么修改,都不会影响到对方
      • 基于引用数据类型的拷贝分为浅拷贝和深拷贝,浅拷贝是当拷贝双方对各自的属性做出修改,对方的属性也会受到同样的影响;深拷贝就是一旦拷贝成功,拷贝对象双方无论对属性进行怎样的修改,都不会影响到对方。

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

  • 相关阅读:
    Word pair Hu
    [bzoj1601] 灌水
    小木棍
    雇佣计划
    [Luogu1282] 多米诺骨牌
    [Luogu1216] 数字三角形
    [Luogu1734] 最大约数和
    [NOIp2008] 传纸条
    [Luogu1325] 雷达安装
    nginx
  • 原文地址:https://www.cnblogs.com/No-harm/p/9512786.html
Copyright © 2011-2022 走看看