JavaScript學習系列以內存模型篇

一個熱愛技術的菜鳥...用點滴的積累鑄就明日的達人javascript

正文
  若是真的想學好一門語言,那麼必定要了解它內存模型,本篇文章就帶你走進JavaScript的內存模型,因爲本人才疏學淺,如有什麼表述有誤的地方,歡迎各位看官可以指點一二,在此不勝感激...
  在閱讀這邊文章以前,默認您已經掌握了JavaScript的基本概念、棧堆等基本數據結構以及計算機基本理論基礎,若有了解欠缺,請移步相關博客後再閱讀本文。
1、基本的數據類型的內存結構
  首先粗略的介紹一下JavaScript中五種基本的數據類型Undefined、Null、Boolean、Number、String;其中對於Undefined與Null的區別,網上有不少大牛都有介紹,在此本文暫不涉及,若有疑慮之處,請移步相關博客。或許有看官會問爲何在介紹JavaScript內存模型以前要先介紹JavaScript的基本數據類型的內存結構呢?這是由於JavaScript內存模型與基本數據類型的內存結構的關係就比如數學與實數的關係,基本數據類型的內存結構是整個JavaScript內存模型的基礎。那麼接下來就讓我以最簡短的方式來闡述一下基本數據類型的內存結構吧~
  基本數據類型的內存結構:在JavaScript中基本的數據類型都是以值的形式保存在內存中的。舉個例子:
 
var inta = 10;
var strb = 'Hello';

  那麼在執行完這段JavaScript代碼以後,內存中會有兩個區域分別表示爲inta,strb;其中表示inta區域的值爲‘10’,表示strb區域的值爲‘Hello’,也即表示inta與strb的內存區域保存的均爲實際的真值; java

2、引用數據類型的內存結構算法

  在JavaScript中除了基本數據類型,那就剩下引用數據類型了,因此在介紹玩基本數據類型內存結構以後,就頗有必要再介紹一下引用數據類型內存結構。引用數據類型的真實對象是保存在堆內存中的,而JavaScript與Java類似,均不能夠直接訪問堆內存,因此都是使用「引用」這個東西來訪問處於堆中的對象,引用與對象的關係能夠描述成遙控器與電視機之間的關係,咱們能夠持有遙控器來操控電視機。所謂的引用其實就是一塊內存的地址,即在表示引用的區域上保存的是內存中對象的內存地址值,如圖所示:瀏覽器

  其中假設對象處於內存中一個位置叫作0x23215的區域,那麼橢圓的區域表示這個對象的引用,橢圓區域中存的就是0x23125這個值,在實際的操做中執行環境會經過引用中存的0x23125,去找到內存中的這個對象。數據結構

3、內存模型閉包

  在JavaScript執行時期,能夠將內存從邏輯上劃分爲兩部分:棧與堆。其中棧是在JavaScript執行時,用於儲存執行上下文(後續文章會介紹)的,而堆是存儲對象的區域。在執行上下文生成以後,會建立一個變量對象(後續文章會介紹),變量對象是一個特殊的對象,它也會存儲在堆。基本數據類型每每都會直接保存在變量對象中,而引用數據類型其實是在變量對象中保存一個引用指向對象的地址(也即引用自己)。函數

 

  學習完JavaScript中的內存模型以後,請各位看官看看下面這段代碼,而且猜猜它的輸出結果,以驗證上述知識的理解程度:性能

var inta = 10;
var stra = 'Hello';

var obja = {a: 10, b: 'Hello'};

var intb = inta;
var strb = stra;
var objb = obja;

intb = 20;
strb = 'World';
objb.a = 20;
objb.b = 'World';

console.log(inta, intb);
console.log(stra, strb);
console.log(obja, objb);

  運行結果:學習

10 20
Hello World
{ a: 20, b: 'World' } { a: 20, b: 'World' }

  這其中會涉及到對象的賦值問題,在對基本數據類型賦值的時候,都是將原值賦值到新的對象上,因此改變新的對象的值,並不會影響到原值(由於它們本質上保存的是兩個值);而對引用數據類型賦值則是將引用所指向對象的地址賦值給另外一個引用,而在後續操做中,若是經過新的引用去改變對象中內部的值的話,仍是會影響原來的引用所指向的對象(由於它們本質上保存的是同一個對象)spa

4、內存回收機制

  JavaScript具備自動的垃圾回收機制,也即執行環境會負責代碼的執行過程當中使用的內存,它會按期(週期性)找出哪些再也不使用的對象,而後釋放其內存。目前JavaScript最經常使用的垃圾回收算法爲標記清除算法,垃圾回收機制會經過標記的算法來決定哪些對象是不須要再次使用的,而後再進行清除,也即清理哪些被定義爲垃圾的JavaScript對象。

  上述所述的再也不使用的變量也就是生命週期結束的變量,固然只多是局部變量。全局變量的生命週期直到瀏覽器卸載頁面纔會結束,因此聲明一個全局變量的時候,咱們必定要慎重的考慮,在使用完這個變量的對象以後,咱們是否還在須要這個對象,若是不須要的話,咱們應該手動的將這個變量置爲空,這樣在下一次垃圾回收的時候,就能去釋放這個變量上一次指向的對象(請注意變量與對象的區別)。

  下面請各位看官see一下如下的代碼,來分析一下垃圾回收。

function fun1() {
    var obj = {name: 'csa', age: 24};
}

function fun2() {
    var obj = {name: 'coder', age: 2}
    return obj;
}

var f1 = fun1();
var f2 = fun2();

  在上述代碼中,當執行var f1 = fun1();的時候,執行環境會建立一個{name:'csa', age:24}這個對象,當執行var f2 = fun2();的時候,執行環境會建立一個{name:'coder', age=2}這個對象,而後在下一次垃圾回收來臨的時候,會釋放{name:'csa', age:24}這個對象的內存,但並不會釋放{name:'coder', age:2}這個對象的內存。這就是由於在fun2()函數中將{name:'coder, age:2'}這個對象返回,而且將其引用賦值給了f2變量,又因爲f2這個對象屬於全局變量,因此在頁面沒有卸載的狀況下,f2所指向的對象{name:'coder', age:2}是不會被回收的。

  因爲JavaScript語言的特殊性(閉包...),致使如何判斷一個對象是否會被回收的問題上變的異常艱難,這不只須要咱們有很強的基本功,還須要在之後的項目中積累經驗。最後順便說一句,即便隨着硬件的更新換代以及垃圾回收機制的改進,咱們也不該該忽視垃圾回收的基本理論,由於這是提升代碼性能的關鍵一步,只有這樣咱們才能寫出那些堪稱藝術品的代碼...

相關文章
相關標籤/搜索