JS中的棧和堆


一.棧和堆

棧(stack):棧會自動分配內存空間,會自動釋放,存放基本類型,簡單的數據段,占據固定大小的空間。
基本類型:String,Number,Boolean,Null,Undefined

堆(heap):動態分配的內存,大小不定也不會自動釋放,存放引用類型,指那些可能由多個值構成的對象,保存在堆內存中,包含引用類型的變量,實際上保存的不是變量本身,而是指向該對象的指針。
引用類型:Function,Array,Object

二.區別

:所有在方法中定義的變量都是放在棧內存中,隨着方法的執行結束,這個方法的內存棧也自然銷毀。

優點:存取速度比堆快,僅次於直接位於CPU中的寄存器,數據可以共享;
缺點:存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。

:堆內存中的對象不會隨方法的結束而銷毀,即使方法結束后,這個對象還可能被另一個引用變量所引用(參數傳遞)。創建對象是為了反復利用,這個對象將被保存到運行時數據區。

三.棧和堆的溢出

:可以遞歸調用方法,這樣隨着棧深度的增加,JVM維持着一條長長的方法調用軌跡,知道內存不夠分配,產生棧溢出。
:循環創建對象,通俗點就是不斷的new 一個對象。

下面來看看傳值和傳址的區別
其實這兩者區別就是基本類型和引用類型的區別,話不多說看栗子

var a = [1,0,9,8,7]; var b = a; var c = a[0]; console.log(b); //[1,0,9,8,7] console.log(c); //1 //改變數值 b[1] = 3; c = 5; console.log(b[1]); //3 console.log(a[0]); //1 

因為a是數組,是引用類型,賦給b的時候傳的是棧中的地址,不是堆內存中的對象,c僅僅是從a堆內存中獲取的一個數據值,並保存在棧中,所以b修改的時候,會根據地址回到a堆中修改,c則直接在棧中修改,並且不能指向a堆內存中。

四.深淺拷貝

深淺拷貝在前端面試中經常被問到,和大家分享一下,先來說說淺拷貝
淺拷貝:也就是只復制了第一層屬性,復制對象是基本類型
在復制基本類型時,直接使用等號完成,在復制引用類型時,循環遍歷對象,對每個屬性或值使用等號完成。

下面看個栗子

var color1 = ['red','green']; var color2 = []; //復制 for(var i = 0;i < color1.length;i++){ color2[i] = color1[i]; } console.log(color2); //[red,green] color1.push('black'); console.log(color2); //[red,green] 

在這個栗子中,color2復制color1,因為數組中的每一項都是基本類型(string),假如數組中的某一項保存的是一個對象,或者是一個數組,又或者說對象的某一個屬性還是一個對象(也就是引用類型的某個屬性還是引用類型),此時淺拷貝就沒用了,那該怎么辦?
我們先來看一個引用類型屬性還是引用類型的栗子(有點繞口.....)

var person = { name : 'wang', score:{ math:100, English:100 } } 

在上面這個小栗子中,score屬性還是一個對象。

下面繼續來說我們的拷貝,現在該深拷貝出場了......
深拷貝:對屬性中所有引用類型的值,遍歷到是基本類型的值為止,利用遞歸來實現深拷貝。
來看一個栗子

function cloneObject (obj) { var newObj = {} //如果不是引用類型,直接返回 if (typeof (obj) !== 'object') { return obj } //如果是引用類型,遍歷屬性 else{ for (var attr in obj) { //如果某個屬性還是引用類型,遞歸調用 newObj[attr] = cloneObject(obj[attr]) } } return newObj } 

對於深拷貝,我們先判斷它是否為引用類型,如果不是,直接返回
如果是,循環遍歷該對象的屬性,如果某個屬性還是引用類型,則針對該屬性再次調用deepClone函數。

https://www.jianshu.com/p/67c0323aef1e


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM