首頁  >  文章  >  web前端  >  一張紙搞懂JS系列(2)之JS內存生命週期,棧內存與堆內存,深淺拷貝

一張紙搞懂JS系列(2)之JS內存生命週期,棧內存與堆內存,深淺拷貝

coldplay.xixi
coldplay.xixi轉載
2020-09-29 16:18:092613瀏覽

一張紙搞懂JS系列(2)之JS內存生命週期,棧內存與堆內存,深淺拷貝

寫在最前面:在javascript欄位下這是我即將開始寫的一個系列,主要是在框架橫行的時代,雖然上班用的是框架,但是對於面試,以及技術進階,JS基礎知識的鋪墊是錦上添花,也是不得不學習的一塊知識,雖然開汽車的不需要很懂汽車,只需要掌握汽車的常用功能即可。但是如果你懂車,那你也能更好地開車,同理。當然,一篇文章也不會光光只講一個知識點,一般會將有關聯的知識點串聯起來,一邊記錄自己的學習,一邊分享自己的學習,互勉!如果可以的話,也請給我按讚,你的讚也能讓我更努力地更新!

概覽

  • 食用時間:6-12分鐘
  • 難度:簡單,別跑,看完再走

JS記憶體生命週期

  • #分配記憶體

  • 記憶體的讀與寫

  • #釋放記憶體

堆疊記憶體與堆疊記憶體

JS資料型別

在講棧記憶體與堆疊記憶體之前,大家應該都知道JS分為兩種資料型態:

  • 基本資料型別

    #String , Number , Boolean , null , undefined , Symbol (大小固定,體積輕量,相對簡單)

  • 引用資料型別

    #Object , Array , Function (大小不一定,佔用空間較大,相對複雜)

記憶體儲存機制

var a=true;      //布尔型,基本数据类型var b='jack';    //字符型,基本数据类型var c=18;        //数值型,基本数据类型var d={name:'jack'};   //对象,引用数据类型var d=[0,1,2,3,4,5];   //数组,引用数据类型复制代码

正是因為資料類型的不同,所以他們的存放方式也不同,就和現實生活中窮人和富人的住所完全不一樣(扯遠了)。我們先來看一張圖:

一張紙搞懂JS系列(2)之JS內存生命週期,棧內存與堆內存,深淺拷貝

可以看到, a , b , c 都是基本資料類型, de 都是引用資料類型,他們在存放方式上有著本質性的區別,基本資料類型的值是存放在堆疊記憶體中的,而引用資料型別的值是存放在堆疊記憶體中的,堆疊記憶體中僅存放著它在堆疊記憶體中的引用(即它在堆疊記憶體中的位址),就和它的名字一樣,引用資料型別

記憶體存取機制

上面講的是存儲,接下來說一下變數的訪問,基本資料型別可以直接從堆疊記憶體中存取變數的值,而引用資料型別要先從堆疊記憶體中找到它對應的參考位址,再拿著這個引用位址,去堆記憶體中查找,才能拿到變數的值

深淺拷貝

  • 淺拷貝

    上面已經和大家說過了基本資料型別跟引用資料型別在儲存上的不同,那麼,接下來說的這個深淺拷貝,想必大家也在面試題中常常碰到,老方式,先來看一段程式碼

    var name='jack';var obj={  age:24};var nameCopy=name;var objCopy=obj;
    
    nameCopy='bob';
    objCopy.age=15;console.log(name);    //jackconsole.log(obj.age);     //15复制代码

    你會發現,name 是沒有被影響的,而我們命名是修改objCopy.age,為什麼還會影響到obj.age呢,這就是因為深淺拷貝的問題在搗鬼,先來看下下面的一張圖

一張紙搞懂JS系列(2)之JS內存生命週期,棧內存與堆內存,深淺拷貝

之所以會出現這種情況,是因為JS對於基本類型和引用類型的,當我們在複製引用類型的時候,複製的是該物件的引用地址,所以,在執行var objCopy=obj; 的時候,將obj引用地址複製給了objCopy,所以,這兩個物件實際指向的是同一個對象,即改變objCopy 的同時也改變了obj 的值,我們將這種情況稱為淺拷貝,僅僅複製了物件的引用,並沒有開闢新的內存,拿人手短,拷貝地太淺了。 (只有引用型別才會出現淺拷貝的情況)

  • #深拷貝

    再來看接下來的一段程式碼

    var name='jack';var obj={  age:24};var nameCopy=name;var objCopy=JSON.parse(JSON.stringify(obj));
    
    nameCopy='bob';
    objCopy.age=15;console.log(name);    //jackconsole.log(obj.age);     //24复制代码

    可以發現,在經過JSON.parse(JSON.stringify(obj)) 轉換了以後,淺拷貝不復存在,這一波是深拷貝,深拷貝開闢了新的堆內存地址,並且將對象的引用指向了新開闢的內存地址,和前面複製的對象完全獨立,自立根生,拷貝地很深,學功夫學到家,自立門戶的感覺。

  • 另外实现深拷贝的方法(更多方式请自行百度)

    var objCopy=Object.assign({},obj);   //对象深拷贝的方法 Object.assign
    var arrayCopy=array.concat();       //数组深拷贝的方法  concat()  (数组无嵌套对象或者数组可用)
    var arrayCopy=array.slice();       //数组深拷贝的方法  slice()   (数组无嵌套对象或者数组可用)
    JSON.parse(JSON.stringify(array))     //顺带提下,JSON.parse(JSON.stringify())   数组和对象通用复制代码

    接着上面的数组容易踩坑的地方 ,来看一个例子

    var array = [{name: 'jack'}, ['old']];var arrCopy = array.concat();
    arrCopy[0].name='new';console.log(array); // [{name: 'new'}, ['old']]console.log(arrCopy); // [{name: 'new'}, ['old']]复制代码

    可以清楚地看到(数组无嵌套对象或者数组可用的情况下用 concatslice 才有效)

系列目录

更多相关免费学习推荐:javascript(视频)

以上是一張紙搞懂JS系列(2)之JS內存生命週期,棧內存與堆內存,深淺拷貝的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除