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

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

  • 相关阅读:
    Study Plan The Twelfth Day
    Study Plan The Fifteenth Day
    Study Plan The Seventeenth Day
    Study Plan The Tenth Day
    Study Plan The Eighth Day
    Study Plan The Eleventh Day
    Study Plan The Sixteenth Day
    Study Plan The Thirteenth Day
    Study Plan The Fourteenth Day
    Study Plan The Ninth Day
  • 原文地址:https://www.cnblogs.com/No-harm/p/9512786.html
Copyright © 2011-2022 走看看