胡扯JS系列-記憶體模型和函式執行

胖先森發表於2019-01-07

準備寫點亂七八糟的文章,對JavaScript的胡扯

賦詩一首

物件本無根,

型別亦無形。

本來無一物,

何處惹塵埃?

一、JavaScript的記憶體模型

JavaScript的本質是一個物件,一個物件可以包含多個屬性,物件的屬性可以分為直接量和物件兩種型別,而物件又分為Object物件和function物件兩種型別。

按照資料型別劃分:

  • 簡單資料型別
    • number
    • string
    • boolean
  • 特殊資料型別
    • null
    • undefined
  • 複雜資料型別
    • object
      • Object物件
      • function物件

直接量和物件的兩種型別的屬性在記憶體中儲存方式不同(跟Java中的類似)

  • 直接量:直接用兩塊記憶體分別儲存屬性名和屬性值

    胡扯JS系列-記憶體模型和函式執行

  • 物件:需要三塊記憶體,分別儲存屬性名、屬性地址和屬性內容

    胡扯JS系列-記憶體模型和函式執行

對於物件型別的屬性來說,屬性名知識指向了儲存物件的記憶體地址,而不是執行實際的物件,程式碼演示如下:

function F(){
    this.v = 1;
}
var f1 = new F();
var f2 = f1;
console.log(f2.v);
f2.v = 2;
console.log(f1.v);
f1 = null;
console.log(f2.v);

複製程式碼

程式碼的執行圖解:

胡扯JS系列-記憶體模型和函式執行

我們一直都說JavaScript是指令碼語言,在瀏覽器中解釋執行的,不應該有自己的記憶體模型,其實不是這樣的。無論編譯語言還是解釋型語言,他們的變數、函式、物件等資料都是儲存在記憶體當中的,使用時需要通過變數名在指定地方找到對應的具體內容,然後再進行實際操作。

二、在JS中函式是如何執行的

函式我們之前已經都接觸過了,函式無非有兩部分:資料和對資料的操作。資料有分為外部資料內部資料。對於外部資料我們先不進行說明,這裡主要是說函式,內部資料有分為引數變數兩個部分。

引數(形參):在函式每次執行的時候引數都會被賦予一個新的數值;

變數(區域性變數):每次都會設定為一個相同的初始值;

  • 函式的變數和引數是如何儲存的呢?

    函式在每次執行之前都會新建一個引數陣列和一個變數陣列(當然也可以合併為一個陣列,而通常會使用棧來實現),然後將呼叫時所傳遞的引數設定到引數陣列中,而變數陣列在每次執行都具有相同的內容。簡單的資料會直接儲存在陣列當中,而複雜的資料,陣列只是儲存地址,具體的資料儲存在堆中。

    胡扯JS系列-記憶體模型和函式執行

    function paramTest(p1){
        var message = "Hello World";
        console.log(p1);
        for(var i in arguments){
            console.log(arguments[i]);
        }
    }
    //函式的呼叫
    paramTest("a","b","c");
    //輸出結果為: a a b c
    複製程式碼

    我們使用了Chrome的除錯,函式在執行時會將引數p1和函式中所用到的變數messag、i方法相同的地位,即在函式內部執行的時候不會區分是引數還是變數。在JS的函式中,會自動建立一個名字為arguments的內部變數,然後將所有的引數的地址儲存到其中。arguments 類似陣列物件,可以通過它來獲取函式呼叫時所傳遞的引數。

    胡扯JS系列-記憶體模型和函式執行

    paramTest方法首先列印了p1的值,然後遍歷列印arguments中所有的引數的值,可以看出引數p1的值和arguments[0]的值是一樣的,函式的引數按照順序依次儲存在arguments變數中,在呼叫函式時傳入引數的個數也可以和定義時不一樣,所以說JS中不存在同名函式的過載方法。

  • 在函式定義的變數時函式級作用域而不是塊級作用域

    function scopeTest(){
        if(true){
            var message = "Hello World";
        }
        console.log(message);
    }
    //函式的呼叫
    scopeTest();
    //輸出結果為:Hello World
    複製程式碼

    這裡的message是在if語句塊中定義的,但是在if語句外部依然可以進行呼叫。

    在JS中的方法執行時會將其自身所有使用var定義的變數統一放到前面介紹的變數陣列當中,所以在一個函式中,所有使用var定義的變數都是同等地位的

相關文章