js 中的 堆棧


1.含義及對比

堆和棧都是運行時內存中分配的一個數據區,因此也被稱為堆區和棧區;

二者存儲的數據類型和處理速度不同;

(heap)用於復雜數據類型(引用類型)分配空間,例如數組對象、object對象;它是運行時動態分配內存的,因此存取速度較慢。

(stack)中主要存放一些基本類型的變量和對象的引用,(包含池,池存放常量),其優勢是存取速度比堆要快,並且棧內的數據可以共享,但缺點是存在棧中的數據大小與生存期必須是確定的,缺乏靈活性,

先進后出,后進先出原則,所以 push 優於 unshift

1.1 擴展: 隊列(先進先出(FIFO)的數據結構,這是事件循環(Event Loop)的基礎結構)

1.2 經典面試題

var a = 20;
var b = a; // b 為棧類型,相當於新開一塊空間然后賦值為 20,不影響原來的a
b = 30;
console.log(a)
console.log(b)
//20 30

 

var a = { name: '前端開發' }
var b = a;
b.name = '進階';
console.log(a)
console.log(b)
// { name: '進階' }  name: '進階' }

 

var a = { name: '前端開發' }
var b = a;
a = null;    //釋放引用
console.log(a)
console.log(b)
// null { name: '前端開發' }

 

var a = {n: 1};
var b = a;
a.x = a = {n: 2};   //   等價於  b.x = a = {n: 2};            先是預編譯ab同時指向的對象增加x屬性,該對象也就是后來都沒變的b指向的對象,這里  a= {n: 2};改變了a的指向。

另外擴展下連等算法:  var a=b=1,b為全局變量了      function t(){ var var a=b=1}    t()      b // 1    a  // undefined
console.log(a.x);
console.log(b.x);
// undefined {n:2}

 

 

1.3  閉包中的變量並不保存中棧內存中,而是保存在堆內存中,這也就解釋了函數之后之后為什么閉包還能引用到函數內的變量。

function A() { let a = 1 function B() { console.log(a) } return B }

1.4 垃圾回收算法  ( 常見內存泄漏:全局變量、定時器、閉包、dom引用 )

  • 引用計數(現代瀏覽器不再使用)     循環引用 問題  function cycle() { var o1 = {}; var o2 = {}; o1.a = o2; o2.a = o1; return "cycle reference!" } cycle();
  • 標記清除(常用)  從根部(在JS中就是全局對象)出發定時掃描內存中的對象,凡是能從根部到達的對象,保留。那些從根部出發無法觸及到的對象被標記為不再使用,稍后進行回收。

 

2.例子

var a=3;
var b=3;
先處理 var a=3;,首先會在棧中創建一個變量為a引用,然后查找棧中是否有3這個值,如果沒有找到,就將3存放進來,然后將a指向3。
接着處理 var b=3;,在創建為b的引用變量后,查找棧中是否有3這個值,因為此時棧中已經存在了3,便將b直接指向3。這樣,就出現了a與b同時指向3的情況。
此時,如果再令a=4,那么JavaScript解釋引擎會重新搜查棧中是否有4這個值,如果已經有了,則直接將a指向這個地址。沒有的話直接壓入並指向它。


var fruit_1="apple";
var fruit_2="orange";
var fruit_3="banana";
var oArray=[fruit_1,fruit_2,fruit_3];  (此時相當於新建一個包含三個值的數組,與 fruit等不再相關)
var newArray=oArray;
當創建數組時,就會在堆內存創建一個數組對象,並且在棧內存中創建一個對數組的引用
變量fruit_1、fruit_2、fruit_3為基本數據類型,它們的值直接存放在棧中
newArray、oArray為復合數據類型(引用類型),他們的引用變量存放在棧中, 指向於存放在堆中的實際對象。

比較
var str=new String('abc');
var str='abc';
第一種是用new關鍵字來新建String對象,對象會存放在堆中,每調用一次就會創建一個新的對象,而不管其字符串值是否相等及是否有必要創建新對象,從而加重了程序的負擔。並且堆的訪問速度慢。
第二種是在棧中,棧中存放值‘abc’和對值的引用;這種寫法在內存中只存在一個值,有利於節省內存空間。同時它可以在一定程度上提高程序的運行速度,因為存儲在棧中,其值可以共享,並且由於棧訪問更快;
var str1='abc';
var str2='abc';
alert(str1==str2); // true
alert(str1===str2); // true

var str1=new String('abc');
var str2=new String('abc');
alert(str1==str2); // false
alert(str1===str2); // false


3.細節

JavaScript堆不需要程序代碼來顯示地釋放,因為堆是由自動的垃圾回收來負責的,每種瀏覽器中的JavaScript解釋引擎有不同的自動回收方式

一個最基本的原則是:如果棧中不存在對堆中某個對象的引用,那么就認為該對象已經不再需要,在垃圾回收時就會清除該對象占用的內存空間。

因此,在不需要時應該將對對象的引用釋放掉(newArray=null;),以利於垃圾回收,這樣就可以提高程序的性能。

 

4. 相關文章

JavaScript是如何工作的:引擎,運行時和調用堆棧的概述!

js 堆棧

 


免責聲明!

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



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